2010-11-03 73 views
1

我很難弄清楚爲什麼類似查詢的執行時間相差很遠。我有一個簡單SELECT這樣的查詢:奇怪的MySQL 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`) 

任何想法可能會導致第二個查詢跑這麼慢?

回答

1

我有幾個建議。

首先,我會添加一個多列索引來覆蓋這3列。這樣,您就可以掃描一個索引,而不是做一個索引合併:

ALTER TABLE load_report_rows 
    ADD KEY location_report_year_idx (location_id,load_report_id,year); 

新的索引使得LOCATION_ID指數有些多餘,所以你可能要考慮刪除它。

其次,我會建議重寫查詢輸入ints作爲整數,而不是字符串。這將避免不必要的隱式類型轉換,這可能會導致性能下降。它可能不是你的具體問題的原因,但我認爲這是一個很好的做法一般:

SELECT 
    `location_id`, 
    `datetime`, 
    `year`, 
    `month`, 
    `load` 
FROM load_report_rows 
WHERE location_id = 16583 
AND load_report_id = 1 
AND year = 2010 
+0

這樣做的伎倆,我的總運行時間從5分鐘下降到44秒。刪除引號似乎沒有任何區別。我猜想當MySQL在執行它之前優化查詢時,字符串會在處理之前自動轉換爲整數。謝謝! – 2010-11-03 23:39:47

0

sending data狀態是指當MySQL實際上通過線路發送數據時。所以緩慢可能是因爲id 18260只是比第一個查詢返回更多的行。

+0

我更新了我的問題,這兩個查詢返回完全8760行,以便不能成爲問題。 – 2010-11-03 15:23:38

2

sending data是一個誤導性的描述。它實際上包括執行查詢花費的時間花費在線上發送結果的時間。 source 1source 2source 3

由於兩個查詢生成的數據量大致相同,所以差異必須處於執行階段。有幾個可能性:

  • 也許三項指標不產生正確的順序一個有用的十字路口時location_id是18260.嘗試添加多列索引@Ike沃克建議。

  • 也許第二個查詢中要返回的行在整個磁盤上都是分段的。這會讓MySQL花費相當多的時間來等待磁盤尋找下一個位置。試試optimizing你的表格。碎片還可能發生在大量使用的索引中,因此也嘗試刪除並重新創建一些索引。

1

我的猜測是緩存。你正在導致MySQL種姓/轉換你的值(字符串/數字)。你所搜索的所有字段都是int,但你傳遞的是一個字符串來搜索。從您搜索的號碼周圍刪除引號,看看會發生什麼。

MySQL可能會將表中的所有值轉換爲字符串以進行比較,而不是將搜索字符串轉換爲數字。您只發布了1個說明查詢,您應該發佈這兩個查看執行路徑是否不同。