SQL - 慢子查询

时间:2013-03-26 11:07:54

标签: mysql sql

首先,我为这个问题的“新手”性质道歉。我在堆栈交换中看到了许多其他缓慢的子查询问题,但我不确定如何将修复应用于我的问题。除了简单的选择,插入等,我对任何SQL都不熟悉。

我有一个打印机监控系统,它可以每隔五分钟将结果记录到一个MySQL表(trends_uint)中,用于各种设备。它记录:设备ID(itemid),时间戳(时钟)和打印页面(value_avg)。从PhpMyAdmin我可以看到表索引是itemid和clock的组合,我猜它们一起提供了一个唯一的值。到目前为止,该表有大约200万行。

我的查询如下:

SELECT
     tu1.itemid AS trends_uint_itemid,
     tu1.clock AS time_value,
     tu1.value_avg AS pages
FROM
     trends_uint tu1
WHERE
    (tu1.clock = (
                     SELECT max(tu2.clock)
                     FROM trends_uint tu2
                     WHERE tu1.itemid = tu2.itemid
                  )
    )
ORDER BY tu1.clock DESC;

我尝试做的是为每个设备(itemid)选择最新的值(即最高时钟的value_avg),以便我可以绘制每个打印机打印的页数远。

我尝试为查询运行EXPLAIN,返回以下内容:

id  select_type         table   type    possible_keys   key         key_len     ref                 rows        Extra
1   PRIMARY             tu1     ALL     NULL            NULL        NULL        NULL                1527815     Using where; Using filesort
2   DEPENDENT SUBQUERY  tu2     ref     PRIMARY         PRIMARY     8           zabbix.tu1.itemid   115301      Using index

任何帮助将不胜感激。提前谢谢。

4 个答案:

答案 0 :(得分:1)

这样的查询怎么样:

SELECT ...
FROM trends_uint t
INNER JOIN (
    SELECT MAX(clock) AS clock, itemid
    FROM trends_uint
    GROUP BY itemid
) x ON x.itemid = t.itemid AND t.clock = x.clock

假设您的表中有一个复合索引:itemid + clock(按此特定顺序)

答案 1 :(得分:0)

问题在于子查询的类型为“DEPENDENT SUBQUERY”。这意味着MySQL正在为主查询的每个匹配行运行该子查询一次。如果你说这个表有200万行意味着大约200万次。

尝试使用Group By运算符或使用连接将子查询的逻辑移动到主查询。

答案 2 :(得分:0)

如果使用显式子查询,它会有所不同吗?

SELECT
     tu1.itemid AS trends_uint_itemid,
     tu1.clock AS time_value,
     tu1.value_avg AS pages
FROM
     trends_uint tu1
JOIN

(
     SELECT 
         itemid as theItem
         ,max(tu2.clock) AS LatestTime
     FROM trends_uint tu2
     GROUP BY itemid
) LatestClockForEachItem

ON tu1.itemid = LatestClockForEachItem.theItem
AND tu1.clock = LatestClockForEachItem.LatestTime

ORDER BY tu1.clock DESC;

PS。 SQL小提琴:http://sqlfiddle.com/#!2/bac3b/2

答案 3 :(得分:0)

您的查询没问题。您需要trends_uint(itemid, clock)上的索引。

您还可以将子查询表示为:

tu1.clock = (
                     SELECT tu2.clock
                     FROM trends_uint tu2
                     WHERE tu1.itemid = tu2.itemid
                     order by tu2.clock desc
                     limit 1
                  )

对于ma来说,这个表单更清楚了如何使用索引(进入项目的索引,选择最后一个时钟值)。

我还建议您在表中包含一个自动递增ID作为主键。这可以帮助您加快查询,同时尝试获取表中最新的行。