我很难弄清楚为什么类似查询的执行时间彼此差异很大。我有一个简单的SELECT
查询,如下所示:
SELECT
`location_id`,
`datetime`,
`year`,
`month`,
`load`
FROM load_report_rows
WHERE location_id = '16583'
AND load_report_id = '1'
AND year = '2010'
此查询在0.1837秒内快速运行,但如果我将location_id
更改为“18260”,则查询突然需要2.7012秒。 WHERE
子句中使用的所有三个字段都被编入索引,两个查询都返回8760行。此查询的EXPLAIN
将返回以下信息:
id 1
select_type SIMPLE
table load_report_rows
type index_merge
possible_keys load_report_id,location_id,year
key location_id,load_report_id,year
key_len 4,4,4
ref NULL
rows 3349
extra using intersect(location_id,load_report_id,year); using where
MySQL查询分析器为每个查询提供以下内容:
+--------------------------------+----------+----------+
| Status | Query 1 | Query 2 |
+--------------------------------+----------+----------+
| starting | 0.000023 | 0.000023 |
| checking query cache for query | 0.000072 | 0.000068 |
| checking permissions | 0.000010 | 0.000068 |
| opening tables | 0.000012 | 0.000012 |
| system lock | 0.000005 | 0.000004 |
| table lock | 0.000008 | 0.000008 |
| init | 0.000050 | 0.000026 |
| optimizing | 0.000030 | 0.000014 |
| statistics | 0.000461 | 0.001048 |
| preparing | 0.000022 | 0.000043 |
| executing | 0.000003 | 0.000004 |
| sending data | 0.100939 | 2.649942 |
| end | 0.000013 | 0.000040 |
| end | 0.000004 | 0.000004 |
| query end | 0.000004 | 0.000004 |
| freeing items | 0.000012 | 0.000013 |
| closing tables | 0.000008 | 0.000008 |
| logging slow query | 0.000002 | 0.000003 |
| cleaning up | 0.000006 | 0.000005 |
+--------------------------------+----------+----------+
sending data
阶段在第二次查询时需要更长的时间。包含哪些步骤?如果有帮助,这是相关字段的表结构:
`id` int(11)
`load_report_id` int(11)
`location_id` int(11)
`datetime` datetime
`year` int(4)
`month` int(2)
`load` decimal(16,8)
PRIMARY KEY (`id`)
KEY `load_report_id` (`load_report_id`)
KEY `location_id` (`location_id`)
KEY `year` (`year`)
KEY `month` (`month`)
任何可能导致第二个查询运行缓慢的想法?
答案 0 :(得分:2)
sending data
是一种误导性描述。它实际上包括两个执行查询所花费的时间和通过网络发送结果所花费的时间。 source 1 source 2 source 3
由于两个查询都生成大约相同数量的数据,因此差异必须在执行阶段。有几种可能性:
当location_id
为18260时,可能三个索引没有按正确的顺序生成有用的交集。尝试添加多列索引,如@Ike Walker建议的那样。
可能在第二个查询中返回的行在整个磁盘上都是碎片。这将使MySQL花费大量时间等待磁盘寻找下一个位置。试试你的桌子optimizing。使用频繁的索引也会发生碎片,因此请尝试删除并重新创建一些索引。
答案 1 :(得分:1)
我有几点建议。
首先,我会添加一个多列索引来覆盖这3列。这样您就可以扫描单个索引而不是进行索引合并:
ALTER TABLE load_report_rows
ADD KEY location_report_year_idx (location_id,load_report_id,year);
新索引使得location_id索引有点多余,所以你可能也想考虑删除它。
其次,我建议重写查询以将整数输入为int而不是字符串。这将避免不必要的隐式类型转换,这可能导致性能降低。这可能不是你特定问题的原因,但我认为这是一个很好的做法:
SELECT
`location_id`,
`datetime`,
`year`,
`month`,
`load`
FROM load_report_rows
WHERE location_id = 16583
AND load_report_id = 1
AND year = 2010
答案 2 :(得分:1)
我的猜测是缓存。您正在使MySQL吞噬/转换您的值(字符串/数字)。您正在搜索的所有字段都是int,但是您要将mysql传递给要搜索的字符串。从您搜索的数字周围删除引号,看看会发生什么。
MySQL可能会将表中的所有值转换为字符串以进行比较,而不是将搜索字符串转换为数字。您只发布了1个解释查询,您应该发布两个以查看执行路径是否不同。
答案 3 :(得分:0)
sending data
状态是指MySQL实际通过网络发送数据的时间。所以缓慢很可能是因为id 18260只返回比第一个查询多得多的行。