MySQL" IN"使用子查询查询速度非常慢,但使用显式值快速查询

时间:2011-02-16 15:23:29

标签: 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')

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

SELECT
COUNT(DISTINCT subscriberid)
FROM
em_link_data
WHERE
linkid in (24899,24900,24901,24902);

然后查询将在不到1毫秒的时间内运行。子查询单独运行不到1毫秒,列linkid被编入索引。

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

4 个答案:

答案 0 :(得分:23)

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

答案 1 :(得分:4)

是的,带有子查询的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'

确保您已在em_link_data.linkidem_link.id上定义了索引。

答案 2 :(得分:4)

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

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

  • campaignidlink上添加索引,因为FrustratedWithFormsDesigner说
  • 通过执行EXPLAIN SELECT ...
  • 检查子查询是否正确使用索引
  • 启用并调整查询缓存,因为这样可以加快多次调用的子查询

还有一个想法是安装MySQL proxy并编写一个拦截查询的小脚本并重写它以使用连接。

答案 3 :(得分:0)

如果你的子查询很快,那么campaignid和链接绝对是索引的。 l.id是PK并且聚集因此很快。 但据我记得(从上次我检查过这个主题),mysql描述了它的内部优化" in"子查询使用子查询结果的索引排序来提高性能,并在" IN"的左侧使用缓存。将它拖到子查询中更快,如果索引设置为true,则它必须没有这种差异才能使用内连接或" IN"而不是缓存,这可能是由于缓存问题和海量数据。 http://dev.mysql.com/doc/internals/en/transformation-scalar-in.html

我不知道软件的情况,但如果您可以使用INNER JOIN并且在外部查询的WHERE子句中的IN子句之前(可能)有一些额外的定义,请确保将该子句移动到通过临时INNER JOIN进入主INNER JOIN之前的行为类似于干预"其中"子句顺序并减少JOIN中的交叉比较次数,如下所示:

SELECT ... FROM t
INNER JOIN (SELECT 1) AS tmp ON t.asd=23
INNER JOIN t2 ON ...

正常和临时联接查找的示例比较:1000 * 1000> 1000 +(100 * 1000)

此外,似乎子查询被常量val过滤,因此如果是我,我会将子句放在生成结果集的子查询中,并减少JOIN中的比较次数,如下所示:

SELECT ... FROM t
INNER JOIN (SELECT ... FROM t2 WHERE constant clauses) AS tbl2 ON ...

无论如何,在" IN"查询,将子查询中的表的任何列与外部查询中的表的任何列进行比较,需要精确索引双方的列(关于复合索引),但仍然可能是缓存问题。

已编辑: 我也很好奇地问:l.campaignid,l.link和l.id上的复合索引是否有意义?