【问题标题】:Alternative of NOT IN On MySQLMySQL 上 NOT IN 的替代方案
【发布时间】:2013-05-29 21:35:58
【问题描述】:

我有一个问题

SELECT DISTINCT phoneNum 
FROM `Transaction_Register` 
WHERE phoneNum NOT IN (SELECT phoneNum FROM `Subscription`) 
LIMIT 0 , 1000000

执行b/c耗时太长Transaction_Register表有数百万条记录 有没有上述查询的替代方法,如果有的话,我将不胜感激。

【问题讨论】:

  • 你想要更快的东西吗,你有更好的选择吗?表的模式是什么,数据分布如何(统计),你有执行计划EXPLAIN吗?你有什么不检点?
  • 用 MariaDb 替换你的 MySQL 二进制文件。对于这种查询,它比 MySQL 好得多。原因是它有一个更好的查询计划器。
  • @Aron SQL 已经存在了一段时间,有许多引擎可供选择,具有不同的功能和成本。如果你把粪便放在铲子或金盘子上,它仍然闻起来很臭。
  • 尝试为您的表添加索引。
  • @Jodrell 你到底在评论什么?每个数据库引擎的每个 SQL 语句的成本都不同。 MySQL 以无法有效使用子查询而闻名。

标签: mysql sql


【解决方案1】:

另一种方法是使用 LEFT JOIN:

select distinct t.phoneNum
from Transaction_Register t
left join Subscription s
  on t.phoneNum = s.phoneNum
where s.phoneNum is null
LIMIT 0 , 1000000;

SQL Fiddle with Demo

【讨论】:

  • 严肃的问题。这会在 MySQL 上提供更好的性能吗?
  • @Jodrell 经过研究,这确实表现得更好+1。
【解决方案2】:

我怀疑LEFT JOIN 是否真的比NOT IN 表现更好。我只是用下面的表结构进行了一些测试(如果我错了请纠正我):

account (id, ....)   [42,884 rows, index by id]
play (account_id, playdate, ...)   [61,737 rows, index by account_id]

(1) 使用LEFT JOIN查询

SELECT * FROM
account LEFT JOIN play ON account.id = play.account_id
WHERE play.account_id IS NULL

(2) 使用NOT IN查询

SELECT * FROM
account WHERE
account.id NOT IN (SELECT play.account_id FROM play)

使用 LIMIT 0 进行速度测试,...

LIMIT 0,->   100      150      200      250
-------------------------------------------------------------------------
LEFT         3.213s   4.477s   5.881s   7.472s
NOT EXIST    2.200s   3.261s   4.320s   5.647s
--------------------------------------------------------------------------
Difference   1.013s   1.216s   1.560s   1.825s

随着我增加限制,差异越来越大


EXPLAIN

(1) 使用LEFT JOIN查询

SELECT_TYPE   TABLE      TYPE   ROWS    EXTRA
-------------------------------------------------
SIMPLE         account   ALL    42,884
SIMPLE         play      ALL    61,737  Using where; not exists

(2) 使用NOT IN查询

SELECT_TYPE          TABLE      TYPE   ROWS   EXTRA
-------------------------------------------------
SIMPLE               account   ALL    42,884  Using where
DEPENDENT SUBQUERY   play      INDEX  61,737  Using where; Using index

LEFT JOIN 好像没有使用索引

逻辑

(1) 使用LEFT JOIN查询

帐户和游戏之间的 LEFT JOIN 后将产生 42,884 * 61,737 = 2,647,529,508 行。然后检查这些行上的 play.account_id 是否为 NULL。

(2) 使用NOT IN查询

二分查找需要 log2(N) 来判断项目是否存在。这意味着 42,884 * log2(61,737) = 686,144 步

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-09-24
    • 1970-01-01
    • 2018-03-08
    相关资源
    最近更新 更多