2012-12-07 76 views
3

首先,我有以下表結構。爲什麼Mysql沒有在使用OR的WHERE子句上使用索引?

Table Document 
    ## DocID ## ## DocName## ## DuplicateID ## 
     1    Doc1  null 
     2    Doc2  null 
     3    Doc3  null 
     4    Doc4   1 

Table FolderTree 
    ## FolderID ## ## MemberDocID ## 
     1    1 
     1    2 
     1    3 

我有DocID, DuplicateID and MemberDocID and FolderID

我的查詢索引是這樣的:

SELECT d.* 
from Document d, FolderTree f 
WHERE (d.DocID = f.MemberDocID or d.DuplicateID = f.MemberDocID) and f.FolderID = 1 
GROUP BY d.DocID ; 

所以基本上我想要從文件夾ID爲1的所有文件及從表中的重複文件。 group by用於維護記錄的唯一性,即不會檢索兩次文檔。

該查詢工作正常,但在大量記錄中變得更慢。下面是解釋輸出。


| select type | table | type | possible_keys | key | rows | extra   | 

    simple  d  range PRIMARY,... PRIMARY 83168 Using temporary.. 
    simple  f  All  DuplicateIDInx Null  108787 Using join buffer 

我關心的是,表F不使用上DuplicateID索引。 我的問題是,爲什麼這樣?有人可以在這個問題上給我啓發。 林使用MySQL 5.x的 謝謝:)

+2

重寫使用'UNION'查詢 - 這是一個共同的技巧,以避免ORs(這是不是很好優化) – zerkms

+0

我已經讀過它,有沒有另一種選擇?在休眠不支持聯盟,我希望這些以後轉換成hql。 :) –

+0

檢查發佈的查詢。你有'd.DuplicateID = f.MemberID',但你在表f中沒有提到'MemberID'。我想這是一個錯字。 –

回答

1

嘗試這個版本:

SELECT d.* 
FROM Document d 
WHERE EXISTS 
     (SELECT * 
     FROM FolderTree f 
     WHERE (d.DocID = f.MemberDocID OR d.DuplicateID = f.MemberDocID) 
      AND f.FolderID = 1 
    ) ; 

而這一次(編輯):

SELECT d.* 
FROM (SELECT 1 AS FolderID 
    ) AS Parameter 
    CROSS JOIN 
    Document d 
WHERE EXISTS 
     (SELECT * 
     FROM FolderTree f 
     WHERE f.MemberDocID = d.DocID 
      AND f.FolderID = Parameter.FolderID 
    ) 
    OR EXISTS 
     (SELECT * 
     FROM FolderTree f 
     WHERE f.MemberDocID = d.DuplicateID 
      AND f.FolderID = Parameter.FolderID 
    ) ; 

我還要補充的化合物(複合)指數在FolderTree (FolderID, MemberDocID)

如果您還沒有索引Document (DuplicateID),也可以添加一個。

通過使用參數在存儲過程中編寫查詢,可能可以更好地解決額外的需求。

+0

我會檢查這一個。謝謝。 –

+0

是否可以將f.FolderID = 1移到exists子查詢之外? –

+0

爲什麼你想把它從那裏移出去? –

1

看起來像正確的索引不存在。你能澄清更多的表結構和查詢。

  1. 解釋在表FolderTree節目DuplicateIDInx索引名稱在查詢中使用f.MemberID列在 「或d.DuplicateID = f.MemberID」。你能否從表格中提到確切的指數定義。
+0

DuplicateIDinx是Document表中的DuplicateID的索引。沒有使用索引類型。我使用innodDB引擎。 –

1

您可以改爲使用in子句,並使用distinct而不是group by。

SELECT distinct d.* 
from Document d 
join FolderTree f on f.MemberDocID in (d.DocID, d.DuplicateID) 
WHERE f.FolderID = 1 

根據SQL Fiddle,這並沒有太大的改變,除了使加入明確的。

如果您改變duplicateid,但是

update document 
set duplicateid = docid 
where duplicateid is null 

並選擇duplicateid

SELECT distinct d.* 
from Document d 
join FolderTree f on f.MemberDocID = d.DuplicateID 
WHERE f.FolderID = 1 

將使用duplicateid

指數