2013-04-30 83 views
1

我無法通過MySQL InnoDB優化器優化請求。 下面的查詢(查詢1)高效運行:MySQL InnoDB採取的執行計劃效率不高

explain select * from ah_problems 
where rnid in (6022342, 6256614, 5842714, 6302489) 
and fieldid in (5,6); 

和計劃(方案1)如下:

id select_type table  type possible_keys     key   key_len ref rows Extra 
= ======  =========== ===== =============================== ============= ======= === ==== ===== 
1 SIMPLE  ah_problems range CONSTRAINTFIELDID,RNID__FIELDID RNID__FIELDID 8   33 Using where 

到目前爲止,一切都很好。

儘管稍微修改查詢(查詢2)下面將採取災難性的執行計劃:

explain select * from ah_problems 
where rnid in (select rec.rnid as record_id from ar_records rec where rnid in (6022342, 6256614, 5842714, 6302489)) 
and fieldid in (5, 6) 

的結果是一樣的,但是計劃(方案2)現在是這樣做的:

id select_type  table  type   possible_keys  key  key_len ref rows  Extra 
= ======    =========== =====   ================== ======== ======= ==== ======= ===== 
1 PRIMARY   ah_problems ALL    CONSTRAINTFIELDID      36177754 Using where 
2 DEPENDENT SUBQUERY rec   unique_subquery PRIMARY   PRIMARY 4  func 1  Using index; Using where 

如果你想知道,新的子查詢...

select rec.rnid as record_id from ar_records rec where rnid in (6022342, 6256614, 5842714, 6302489) 

...沒有什麼比返回四個R更在查詢1中硬編碼的行:

6022342 
6256614 
5842714 
6302489 

因此查詢(1)和(2)是等價的。

猜猜看,我需要查詢2,而不是一個。我想查詢2是作爲查詢1.我嘗試以下高效:

  1. 查詢3:添加FORCE INDEX(RNID_FIELDID)查詢2. MySQL的只是忽略它。

    解釋SELECT * FROM ah_problems力指數(rnid__fieldid) 其中RNID在(從ar_records REC選擇rec.rnid作爲RECORD_ID其中RNID在(6022342,6256614,5842714,6302489)) 和fieldid在(5,6)

執行計劃是一樣的規劃2.

  1. 查詢4:添加ORDER BY RNID, FIELDID查詢3.我的一些其他問題看到,這可能會誘使優化。它沒有幫助。

    解釋SELECT * FROM ah_problems力指數(rnid__fieldid) 其中RNID在(從ar_records REC選擇rec.rnid作爲RECORD_ID其中RNID在(6022342,6256614,5842714,6302489)) 和fieldid在(5,6)爲了通過RNID,fieldid

計劃4現在使用的索引,但行數仍然是災難性的:

id select_type  table  type   possible_keys  key   key_len ref rows  Extra 
= ======    =========== =====   ================== ========  ======= ==== ======= ===== 
1 PRIMARY   ah_problems index        RNID__FIELDID 8    36179307 Using where 
2 DEPENDENT SUBQUERY rec   unique_subquery PRIMARY   PRIMARY  4  func 1  Using index; Using where 

如果這會有所幫助,這是我ah_problems表的定義。很遺憾,我無法改變表格的定義。有什麼我可以做的,使MySQL優化器使用計劃1攻擊查詢2中的表ah_problems

CREATE TABLE `ah_problems` (
    `ID` int(11) NOT NULL AUTO_INCREMENT COMMENT 'Identifier for update statements', 
    `RNID` int(11) NOT NULL COMMENT 'Record number', 
    `FIELDID` int(11) NOT NULL COMMENT 'Which field is value in', 
    `VALUE` varchar(255) NOT NULL COMMENT 'The value the field got on MODIFIED_DATE', 
    `PREVIOUSID` int(11) DEFAULT NULL COMMENT 'Reference to previous value', 
    `MODIFIED_DATE` datetime NOT NULL COMMENT 'When was it changed', 
    `MODIFIED_GROUPID` int(11) DEFAULT NULL COMMENT 'In what group did modified_userid change it', 
    `MODIFIED_USERID` int(11) NOT NULL COMMENT 'Who changed it', 
    PRIMARY KEY (`ID`), 
    KEY `CONSTRAINTFIELDID` (`FIELDID`), 
    KEY `CONSTRAINTMODIFIED_GROUPID` (`MODIFIED_GROUPID`), 
    KEY `CONSTRAINTMODIFIED_USERID` (`MODIFIED_USERID`), 
    KEY `CONSTRAINTPREVIOUSID` (`PREVIOUSID`), 
    KEY `RNID__FIELDID` (`RNID`,`FIELDID`), 
    CONSTRAINT `HPRB_FIELD` FOREIGN KEY (`FIELDID`) REFERENCES `ad_fields` (`ID`), 
    CONSTRAINT `HPRB_MODIFIED_GROUP` FOREIGN KEY (`MODIFIED_GROUPID`) REFERENCES `ap_groups` (`ID`), 
    CONSTRAINT `HPRB_MODIFIED_USER` FOREIGN KEY (`MODIFIED_USERID`) REFERENCES `ap_users` (`ID`), 
    CONSTRAINT `HPRB_PREVIOUS` FOREIGN KEY (`PREVIOUSID`) REFERENCES `ah_problems` (`ID`) ON DELETE CASCADE, 
    CONSTRAINT `HPRB_RN` FOREIGN KEY (`RNID`) REFERENCES `ar_records` (`RNID`) 
) ENGINE=InnoDB AUTO_INCREMENT=72305308 DEFAULT CHARSET=utf8 COMMENT='PTR history'$$ 
+0

如果查詢1和2是等價的,那麼你一定不能被利用工作爲你如果查詢1不起作用,就寫它。是否有一些問題阻止了1的工作?任何信息可能有助於提供更好的答案 – dlp 2013-04-30 16:53:15

+0

查詢1有效。查詢2有效,但速度很慢。實際上,這兩個查詢都試圖找出優化器的問題。我的實際查詢實際上更復雜(添加的子查詢動態獲取要獲取的記錄列表)。 – 2013-04-30 16:56:15

回答

1

MySQL不能優化IN子查詢能領導(只執行一次),它是在一個循環的主查詢每個記錄總是執行。

與聯接替換爲:

SELECT ahp.* 
FROM ar_records ar 
JOIN ah_problems ahp 
ON  ahp.rnid = ar.rnid 
     AND ahp.fieldId IN (5, 6) 
WHERE ar.rnid IN (6022342, 6256614, 5842714, 6302489) 
+0

偉大的分析和解釋。謝謝你的時間。 – 2013-04-30 17:06:17

1

我相信MySQL需要的子查詢之前解決WHERE fieldid IN (5, 6)。 嘗試添加以下指標:

ALTER TABLE ah_problems ADD INDEX FIELDID__RNID (FIELDID, RNID); 

如果沒有幫助,重寫查詢爲JOIN

SELECT * 
FROM ah_problems 
JOIN ar_records USING (rnid) 
WHERE rnid in (6022342, 6256614, 5842714, 6302489) 
AND fieldid in (5, 6) 
+0

謝謝。爲你的時間+1。不幸的是,我不能添加索引。我會去參加。 – 2013-04-30 17:05:57