2013-04-03 128 views
0

有没有一种方法来优化以下查询。大约需要11秒:优化复杂GROUP BY查询的性能

SELECT 
    concat(UNIX_TIMESTAMP(date), '000') as datetime, 
    TRUNCATE(SUM(royalty_price*conversion_to_usd* 
      (CASE WHEN sales_or_return = 'R' THEN -1 ELSE 1 END)* 
      (CASE WHEN royalty_currency = 'JPY' THEN .80 
        WHEN royalty_currency in ('AUD', 'NZD') THEN .95 ELSE 1 END)) 
    ,2) as total_in_usd 
FROM 
    sales_raw 
GROUP BY 
    date 
ORDER BY 
    date ASC 

做一个解释,我得到:

1 SIMPLE sales_raw index NULL date 5 NULL 735855 NULL 
+0

这是一个聚合。因为没有WHERE子句,所以没有什么可做的,只是扫描整个表。在这种情况下,这是I/O性能和CPU性能问题(针对您的表达式)。你可以过滤一组(索引)日期,所以你只需要阅读表的一部分? – 2013-04-03 19:35:14

+0

@NWest谢谢你的回复。你能举个例子说明你的意思是“过滤一组索引日期”吗? – David542 2013-04-03 19:47:14

回答

2

这是一个答案,在注释的问题。它格式更好地在这里:

一组索引日期的过滤装置的一个例子做这样的事情:

where date >= AStartDateVariable 
and date < TheDayAfterAnEndDateVariable 

如果在日期字段没有索引,创建一个。

2

您可以加快速度。您好像在date上有索引。发生的事情是,行在索引中被读取,然后每行被查找。如果数据没有按日期字段排序,那么这可能不是最佳的,因为读取将基本上是随机页面。在原始表格而不是适合内存的情况下,这会导致称为“页面抖动”的情况。需要记录,页面从内存中读取(取代内存缓存中的另一页),下一次读取也可能导致缓存未命中。

要看看这是否发生,我会建议两件事之一。 (1)尝试删除date上的索引或将group by条件切换为concat(UNIX_TIMESTAMP(date), '000')。这些中的任何一个都应该将索引作为一个因素去除。

从您的额外评论,这不是发生,虽然指数的好处似乎是在一边。 (2)您还可以展开索引以包含查询中使用的所有表。除了日期之外,索引还需要包含royalty_price,conversion_to_usd,sales_or_return和royalty_currency。这将允许索引完全满足查询,而无需在页面中查找额外的信息。

您还可以与您的DBA一起检查,确定您拥有足够大的页面缓存以匹配您的硬件功能。

+0

对于#2,你的意思是所有这些字段的复合索引?或每个独特的索引? – David542 2013-04-03 20:01:15

+0

它看起来像#1减慢了约20%的查询。 – David542 2013-04-03 20:02:52

+0

@GordonLinoff and upvoters:请注意,原则上索引的日期是可取的(http://dev.mysql.com/doc/refman/5.0/en/group-by-optimization.html,第一段)。 #2无法提供帮助,因为日期的第一个索引是检索其他字段所需的全部内容。优化程序很可能会忽略更多索引,因为它们旨在用数据查找行,而不是数据本身。但是,也许你可以在RDMBS中说出一个情况,其中索引仅用于查找数据。 – koriander 2013-04-03 20:50:10

0

这是一个简单的查询组,甚至不涉及连接。我希望问题在于你正在使用的功能。

请从一个简单的查询开始,只是检索日期和conversion_to_usd的总和。检查性能并逐步建立查询,始终检查性能。发现肇事者不应该花很长时间。

Concats通常是缓慢的操作,但我想知道sum之后截断可能会使优化器混淆。第二种情况可以通过加入一个货币代码表和各自的百分比表来加以取代,但这并不明显,这会造成很大的差异。首先发现肇事者。

您也可以存储正确数量的值,但会引入反规范化。