我有以下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'
答案 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