2

我在我的网络应用程序中使用以下查询。它正在查询一个包含给定时间网上商店价格的结果表。它有大约 100 万条记录。索引是 shopID、StartTime、pID 和 WebsiteID 之一。

查询:

SELECT shopID, tresults.StartTime, tresults.Price
FROM tresults
WHERE tresults.pID = 7  
    AND WebsiteID = 1 AND StartTime BETWEEN "2013-4-10" AND "2013-4-11"
    AND tresults.shopID IN (44, 68, 23, 16, 144, 8, 9, 5) 
GROUP BY tresults.StartTime, tresults.Price 
ORDER BY tresults.StartTime, tresults.Price

解释结果:

1, SIMPLE, tresults, index_merge, PRIMARY,idxPID,idxWebsite,idxStartTimeASC,idxStartTimeDESC,fk_shopID, idxPID,idxWebsite, 4,4, , 1062, Using intersect(idxPID,idxWebsite); Using where; Using temporary; Using filesort

对我来说看起来不错,但查询仍然需要大约一秒钟才能完成。这在快速网站中是不可接受的。

我怎样才能加快速度?

注意:速度看起来取决于 shopID 的数量

谢谢!

4

2 回答 2

3

您的查询并不像您想象的那么好。它使用“使用临时”和“使用文件排序”。这意味着它已保存在您的文件系统中以供解析器操作并使查询变得更慢。

要尝试改进它,您可以尝试使子句 WHERE 中的字段与您在表中获得的索引相匹配。甚至,如果您的查询将始终使用这些元素运行,则按以下顺序创建一个新索引:pID、websiteID、startTime。

我也不明白为什么您的查询中有两次字段 tresults.pID。

[编辑]

嘿,伙计,你得到临时表是因为你使用聚合函数来操作你的结果集,例如 GROUP BY、ORDER BY、HAVING 等等。只要临时表保存在内存中就可以了,这是访问数据的更快方法。问题是当这些表达到这样的大小时,解析器必须将它们带到文件系统中。

您可以尝试找到最佳平衡更改 tmp_table_size 和 max_heap_table_size 的值。此外,一旦内存存储不支持它们,请尽量避免使用博客/文本列。

您可以在官方文档中找到更多信息。

于 2013-04-14T12:18:40.920 回答
1

创建以下索引:

CREATE INDEX idxTresults_pwsp ON tresults (pId, WebsiteID, StartTime, Price);

这是缩小搜索范围的最佳方法,它还可以防止“使用临时”和“使用文件排序”。

mysql> EXPLAIN 
SELECT shopID, tresults.StartTime, tresults.Price
FROM tresults
WHERE tresults.pID = 7  
    AND WebsiteID = 1 AND StartTime BETWEEN '2013-4-10' AND '2013-4-11'
    AND tresults.shopID IN (44, 68, 23, 16, 144, 8, 9, 5) 
GROUP BY tresults.StartTime, tresults.Price 
ORDER BY tresults.StartTime, tresults.Price 
\G
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: tresults
         type: ref
possible_keys: idxpid,idxStarttime,fkShop_id,idxTresults_pwsp
          key: idxTresults_pwsp
      key_len: 9
          ref: const,const
         rows: 1
        Extra: Using where

这样做更好的原因是索引的前两列有助于为特定的 pID 和 WebsiteID 选择正确的行子集。由于您选择了一个特定的 pID 和 WebsiteID,因此这个新索引中的所选条目已经保证按照 StartTime 和 Price 的最佳顺序进行排序,因此查询不需要创建临时表。它只是按照它们存储在索引中的顺序访问条目。

PS:MySQL 不支持“升序”和“降序”索引。它接受关键字,但对它们没有任何不同。因此,您不需要给定列上的两种类型的索引。

PPS:不要对字符串或日期文字使用双引号。使用单引号,以符合 ANSI SQL。如果您曾经使用过其他 RDBMS 品牌,那么养成这个习惯会更好,因为大多数其他品牌根据标准使用引号。MySQL 允许以非标准方式使用双引号。

于 2013-04-15T02:01:43.033 回答