我在我的网络应用程序中使用以下查询。它正在查询一个结果表,其中包含特定时间网上商店的价格。它有大约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的数量
谢谢!
答案 0 :(得分:3)
你的查询并不像你想的那么好。它使用“Using temporary”和“Using filesort”。这意味着它已被保存在您的文件系统中以供解析器操作并使查询更慢。
要尝试改进它,您可以尝试使Clause WHERE上的字段与您在表中获得的索引相匹配。或者甚至按以下顺序创建一个新索引:pID,websiteID,startTime如果您的查询将始终使用这些元素运行。
我也不明白你为什么在你的查询中有两次字段tresults.pID。
[编辑]
嘿,伙伴,你正在获得临时表,因为你正在使用聚合函数来操纵你的结果集,例如GROUP BY,ORDER BY,HAVING等。只要临时表保存在内存中就可以了,这是访问数据的更快捷方式。问题是当这些表达到如此大小以至于解析器必须将它们带到文件系统时。
您可以尝试找到最佳平衡更改tmp_table_size和max_heap_table_size的值。此外,一旦内存存储不支持,请尽量避免使用博客/文本列。
您可以在官方文档中找到更多信息。
答案 1 :(得分: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允许以非标准方式使用双引号。