2013-03-26 166 views
2

首先,我对此问题的“新手”式性质表示歉意。我在堆栈交换中看到了许多其他缓慢子查询的问题,但我不确定如何将修复应用于我的问题。我是相当新的超越简单的选择,插入任何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; 

我想要做的,就是选择了最新的值(即value_avg的最高时钟)为每个设备(itemid的),所以我可以希望绘制出每台打印机到目前为止打印的页数。

我试着运行它返回以下查询的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 

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

回答

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

+0

这样做诀窍:)。感谢您的及时答复,并链接到SQL小提琴。我知道那里有一个JS Fiddle网站,所以我应该为了一个SQL小提琴而猎杀:) – Vasudaprime 2013-03-26 14:11:42

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(在这个特定的顺序)

+0

该解决方案还工作过。感谢您的提示答案:)。 – Vasudaprime 2013-03-26 14:12:43

+0

@Vasudaprime:我在9分钟之前给出了这个答案 - 它和查询完全相同 – zerkms 2013-03-26 19:37:34

0

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

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

+0

**在内部的mysql中的EVERY **子查询被重写(通过优化器)到一个相关的子查询中(尽管由于某种原因,我无法快速找到证据为此;但我记得我已经在一些有信誉的来源阅读过) – zerkms 2013-03-26 11:16:59

+0

我应该详细说明,作为一个从属子查询,它引用与外部查询中相同的表。这意味着它必须对来自外部查询的每个可能的组合进行一次评估。由于子查询where子句引用了可能是主键的item_id,因此对于表中的每个记录来说这意味着一次。 – 2013-03-26 11:24:11

+0

是的,我知道。这是一篇关于内部事物的文章,它指出甚至不相关的子查询都被优化器重写为相关的子查询。有一个可能性,只有在子查询执行得很糟糕的旧版本中才有效。 – zerkms 2013-03-26 11:25:32

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 
       ) 

马,这种形式使得它更清晰的指标如何被使用(进入指数的项目,选择最后一个时钟值)。

我还建议你包括表自动递增的ID作为主键。这可以帮助您加快查询,试图获取表中最近的行。