MySQL"IN"查询子查询非常慢,但显式值快

Fra*_*nco 20 mysql query-optimization

我有一个MySQL查询(Ubu 10.04,Innodb,Core i7,16Gb RAM,SSD驱动器,MySQL params优化):

SELECT
COUNT(DISTINCT subscriberid)
FROM
em_link_data
WHERE
linkid in (SELECT l.id FROM em_link l WHERE l.campaignid = '2900' AND l.link != 'open')
Run Code Online (Sandbox Code Playgroud)

表em_link_data有大约7百万行,em_link有几千行.此查询大约需要18秒才能完成.但是,如果我替换子查询的结果并执行此操作:

SELECT
COUNT(DISTINCT subscriberid)
FROM
em_link_data
WHERE
linkid in (24899,24900,24901,24902);
Run Code Online (Sandbox Code Playgroud)

那么查询将在不到1毫秒的时间内运行.子查询单独运行不到1毫秒,列linkid被索引.

如果我将查询重写为连接,也不到1毫秒.为什么"IN"查询的子查询速度如此之慢以及为什么这么快的值?我无法重写查询(购买软件)所以我希望有一些调整或提示来加速这个查询!任何帮助表示赞赏.

Bri*_*ian 23

每次评估它们时都会执行子查询(无论如何,在MySQL中,并非所有RDBMS),即你基本上运行了700万个查询!如果可能,使用JOIN会将此值减少为1.即使添加索引可以提高性能,您仍然可以运行它们.

  • @Franco:在第二个示例中,您提供了四个标量值。不需要执行子查询,并且比较四个整数非常快。 (2认同)
  • 马丁,谢谢你指点我,你太棒了!我进行了搜索,但没有合适的“语言”来搜索这个。这解释了它是一个优化器错误,否则它根本没有意义。@Brian:我提供了 4 个标量作为我想象的理想优化器会做的示例,即首先执行独立子查询并缓存结果;然后它的行为就像我想象的标量版本一样。 (2认同)

awm*_*awm 6

是的,IN子查询很慢。改用连接。

SELECT
COUNT(DISTINCT subscriberid)
FROM em_link_data JOIN em_link ON em_link_data.linkid=em_link.id
WHERE em_link.campaignid = '2900' AND em_link.link != 'open'
Run Code Online (Sandbox Code Playgroud)

并确保您已在em_link_data.linkid和上定义索引em_link.id


Ale*_*dro 5

问题是 MySQL 从外到内执行查询,而您可能认为您的子查询执行一次,然后将其结果传递给外部查询的 WHERE 表达式(请参阅MySQL 文档)。

如果您无法重写查询,则应进行以下优化:

  • 添加一个索引campaignidlink正如 FrustratedWithFormsDesigner 所说
  • 通过执行检查子查询是否正确使用索引 EXPLAIN SELECT ...
  • 启用和调整查询缓存,因为这应该会加快子查询被多次调用的速度

另一个想法是安装MySQL 代理并编写一个小脚本来拦截您的查询并将其重写为使用连接。