MySQL会自动优化子查询吗?

sau*_*bhj 10 mysql sql

我想运行以下查询:

-- Main Query    
SELECT COUNT(*) FROM table_name WHERE device_id IN 
     (SELECT DISTINCT device_id FROM table_name WHERE NAME = 'SOME_PARA')
Run Code Online (Sandbox Code Playgroud)

以下查询(来自Main Query的子查询):

SELECT DISTINCT device_id FROM table_name WHERE NAME = 'SOME_PARA'
Run Code Online (Sandbox Code Playgroud)

在7秒内执行,从2.1M行的表中提供2691行.

我解除了上面的主查询,并且在等待5分钟后仍在执行.

最后,我分别执行了子查询,从结果中取出了2691条记录,执行了以下查询:

-- Main Query (improvised)    
SELECT COUNT(*) FROM table_name WHERE device_id IN 
     ("device_id_1", "device_id_2", ....., "device_id_2691")
Run Code Online (Sandbox Code Playgroud)

令人惊讶的是,这给了我40秒内的答案.

是什么赋予了?为什么MySQL不使用我使用的相同技术并快速给出答案?难道我做错了什么?

Mar*_*ams 5

不幸的是,MySQL并不擅长使用IN优化子查询.这是来自MySQL文档:

IN的子查询优化不如=运算符或IN(value_list)运算符有效.

IN子查询性能较差的典型情况是子查询返回少量行但外部查询返回大量行以与子查询结果进行比较.

问题是,对于使用IN子查询的语句,优化程序将其重写为相关子查询.请考虑以下使用不相关子查询的语句:

SELECT ... FROM t1 WHERE t1.a IN(SELECT b FROM t2);

优化器将语句重写为相关子查询:

SELECT ... FROM t1 WHERE EXISTS(SELECT 1 FROM t2 WHERE t2.b = t1.a);

如果内部和外部查询分别返回M行和N行,则执行时间变为O(M×N)的量级,而不是O(M + N),就像对于不相关的子查询一样.

这意味着IN子查询可能比使用IN(value_list)运算符编写的查询慢得多,该运算符列出了子查询将返回的相同值.

请尝试使用JOIN.

因为MySQL从内到外工作,有时你可以通过将子查询包含在另一个子查询中来欺骗MySQL,如下所示:

SELECT COUNT(*) FROM table_name WHERE device_id IN
     (SELECT * FROM (SELECT DISTINCT device_id FROM table_name WHERE NAME = 'SOME_PARA') tmp)
Run Code Online (Sandbox Code Playgroud)

这是JOIN解决方案:

SELECT COUNT(DISTINCT t2.id) FROM table_name t1
  JOIN table_name t2
    ON t2.device_id = t1.device_id
  WHERE t1.NAME = 'SOME_PARA'
Run Code Online (Sandbox Code Playgroud)

请注意,我从内部开始也出去了.