2010-08-14 34 views
2

我試圖優化一個需要大約15-20秒才能運行的MySQL查詢。我的數據表有大約10M行,並且查詢試圖返回與144個「運行」字段和35個「名稱」字段匹配的68,000條記錄。因爲查詢使用了兩個子句,所以我的索引似乎不是非常有用。使用兩個「in」子句優化查詢

這裏的查詢:

select * from data d where 
d.data_type='Result' and 
(d.run in ('8a7aee1f2a6232b1012a624da9201b92', '8a7aee1f2a6232b1012a625432a314ef' , 

... [144 runs] 

)) and (d.name like 'itema[%]' or d.name like 'itemb[%]') 

這裏的表定義

CREATE TABLE `data` (
    `data_type` varchar(31) NOT NULL, 
    `id` char(32) NOT NULL, 
    `entry_time` datetime default NULL, 
    `name` varchar(255) NOT NULL, 
    `step` int(11) default NULL, 
    `value` double NOT NULL, 
    `run` char(32) NOT NULL, 
    PRIMARY KEY (`id`), 
    KEY `FK2EEFAA8ECCC6F3` (`run`), 
    KEY `data2` (`run`,`step`), 
    KEY `data3` (`data_type`,`name(10)`,`run`), 
    CONSTRAINT `FK2EEFAA8ECCC6F3` FOREIGN KEY (`run`) REFERENCES `run_archive` (`id`) 
) ENGINE=InnoDB DEFAULT CHARSET=utf8; 

解釋告訴我的查詢使用的關鍵數據3。

id  select_type  table type possible_keys key  key_len ref rows Extra 
1  SIMPLE d range FK2EEFAA8ECCC6F3,data2,data3 data3 223  NULL 113271 Using where 

我曾經運行過144次查詢(每次運行一次)。這似乎是做一個查詢的兩倍,但仍然太慢。

優化建議?想法我有【

  • 找到一個神奇的索引速度
    這件事

  • 反規範化的數據(這將會是 容易擺脫運行,但
    更難名稱)

  • 分裂 不同的表中的數據 (很難與我的Java /休眠 進場做)

或者我只是問在這裏不可能?

編輯:原來最大的修復是增加我的innodb_buffer_pool的大小。這樣做後查詢下降到大約1秒半。我已經標記爲「回答」一個修正,稍微改進了一點。

+0

什麼是where條款中的個人限制的選擇性?即數據類型'結果'有多少行,具有匹配運行的行數以及表中存在匹配名稱的行數? – meriton 2010-08-14 22:06:56

+0

編輯:有data3鍵錯誤。 (我會交代)。第一個字段是data_type。 – 2010-08-14 22:08:08

回答

0

根據上run條件如何選擇,它可能會更好地提供索引

data_type, run, name(10) 

與提供用於前綴索引早匹配列的問題在於,它跨越散射匹配的行該索引需要從磁盤讀取大部分索引。

此外,使用較小的數據類型作爲運行ID將減少索引大小並加快比較速度。這是一個不斷提高的因素,但無論如何可能都是值得的。

+0

這有助於。在我的筆記本電腦上運行,這個索引是78秒,其他索引是135。 – 2010-08-14 23:01:46

1

考慮拆分result記錄離data表嗎?我沒有注意到你的result是多少百分比,但也許值得在你的Prod數據庫的開發副本中進行基準測試。

你可以FK那些run值?如果它們可重用(?),也許創建一個Run表?我的猜測是,144個字符串匹配,甚至索引,如果他們是intsmallint比較慢。再次,基準這個建議或任何建議,顯然將證明這一理論。

當在name屬性中不包含類似子句時,查詢計劃差異是什麼樣的?

+0

有data3鍵錯誤。 (我會交代)。第一個字段是data_type。 – 2010-08-14 22:08:36

+0

大約80%的數據是「result」data_type。另外,我確實有一個運行表 - 「運行」字段是外鍵的運行表,但通過char(32)id。做一個聯合似乎是相同的表現。我使用char(32)而不是整數來實現數據的可移植性(如果我需要在服務器之間移動它)。 – 2010-08-14 22:09:43

+0

用一個in語句替換「like」這個名字,說明36個可能性具有相同的性能。 – 2010-08-14 22:55:30