如何使用子查询优化此查询?

时间:2012-01-26 12:52:23

标签: mysql sql subquery

我有以下MySQL查询:

SELECT value_1, (
    SELECT value_4 
    FROM table_1
    WHERE value_3 < value_1 
    ORDER BY value_3 DESC  
    LIMIT 1
)
AS result_value 
FROM table_2 
WHERE value_1 BETWEEN 1325372400000 AND 1328050800000  
ORDER BY value_1

返回32个结果,运行时间为6.6秒。我们的想法是从table_1获取条目,其中value_3与table_2中的value_1“最接近”。

查询包含的两个查询,即

SELECT value_1
AS result_value 
FROM table_2 
WHERE value_1 BETWEEN 1325372400000 AND 1328050800000  
ORDER BY value_1

和(例如)

SELECT value_4 
FROM table_1
WHERE value_3 < 1328050800000 
ORDER BY value_3 DESC  
LIMIT 1

每次运行需要0.03秒。计算32个结果集的累计时间,复合查询应该不超过1秒,或者可能更少(因为不考虑单个查询的I / O开销)。然而在6.6秒,它需要更长的时间。

为什么,我该如何优化它?或者是否有其他/更好的方式来实现我的目标?

更新

表定义:

table_1(MyISAM,700000条目):

'id', 'int(10) unsigned', 'NO', 'PRI', NULL, 'auto_increment'
'value_3', 'bigint(20) unsigned', 'NO', 'UNI', '0', ''
'value_4', 'bigint(20) unsigned', 'NO', '', '0', ''

table_2(MyISAM,4000条目):

'value_1', 'bigint(20) unsigned', 'NO', 'PRI', NULL, ''

EXPLAIN [查询]:

'1', 'PRIMARY', 'table_2', 'range', 'PRIMARY,value_3_UNIQUE', 'PRIMARY', '8', NULL, '32', 'Using where; Using index'
'2', 'DEPENDENT SUBQUERY', 'table_1', 'index', 'value_3,value_3_value_4', 'value_3', '8', NULL, '1', 'Using where'

3 个答案:

答案 0 :(得分:1)

使用一些mysql kung fu:

SELECT * from
(SELECT value_1, value_4
FROM table_2 
join table_1 on value_3 < value_1
WHERE value_1 BETWEEN 1325372400000 AND 1328050800000  
ORDER BY value_1, value_3 DESC) x
GROUP BY value_1 
ORDER BY value_1

“功夫”是指使用mysql时,如果未分组的列未聚合(例如SUM()等),则会遇到每个组遇到的第一行行。如果您在有序的结果集上使用此技术,则可以获得您所追求的值。

这不仅更容易编码,而且您会注意到只有一次通过表(而不是您尝试的每行一个查询)。它应该表现良好。


编辑:

一些评论者猜测GROUP BY的这种特殊形式是“不确定的”和/或“未得到官方支持”等。documentation表示该行选择为“不确定”,但是我从来没有见过或听说过mysql选择任何行其他而不是第一次遇到的行,并且在内部选择上使用order by被使用并依赖于无数的生产查询。

FWIW,我很乐意将这种方法推荐为“可靠”且具有生产价值。

答案 1 :(得分:1)

如果value_1中的table_2索引和(value3, value4)上的复合table_1索引,则查询将只使用索引。


您也可以尝试此查询:

SELECT value_1
     , value_4 AS result_value 
FROM table_2 
  JOIN table_1
    ON table_1.value_3 =
       ( SELECT value_3
         FROM table_1
         WHERE value_3 < value_1 
         ORDER BY value_3 DESC  
         LIMIT 1
       )
WHERE value_1 BETWEEN 1325372400000 AND 1328050800000  
ORDER BY value_1

答案 2 :(得分:0)

这里我只是避免使用虚拟(派生)表。虚拟表使用背后的主要原因是通过在groupcconcat()中应用order by子句来实现排序。

SELECT SUBSTRING_INDEX(group_concat(value_1 
                                    ORDER BY value_1, value_3 DESC),',',1) as value_1, 
       SUBSTRING_INDEX(group_concat(value_4
                                    ORDER BY value_1, value_3 DESC),',',1) as value_4 
FROM table_2 join table_1 on value_3 < value_1 

WHERE value_1 BETWEEN 1325372400000 AND 1328050800000  

GROUP BY value_1  
ORDER BY value_1