2016-11-17 40 views
0

我正在使用MySQL 5.6,並且在某些非常大的表中遇到了一些查詢性能問題。具體而言,我不確定如何在表格之間同時存在引用以及in()條件時正確索引表格。使用外鍵和範圍進行查詢的索引設計

簡化表如下所示(A和B都是巨大的表,而C是一個小桌子與大約20行,所有的表是InnoDB的)

(ID INT,創建日期時間,VAL INT)

(ID INT,A_ID INT,C_ID INT)

ç(ID INT,VAL INT)

查詢有問題看起來是這樣的:

Select a.id 
    from a 
    join b ON (a.id = b.a_id) 
    where a.created >= now() - interval 90 day 
     and a.val = 0 
     and b.c_id in (
     SELECT id 
      from c 
      where val = 1) 

我已經創建了一個索引爲(VAL,創建ID),一個在B中(C_ID,A_ID),它的偉大工程時,有一個「 ='condition on c_id(例如,c_id = 5)但是使用'in()'條件解釋告訴我,我的A上的索引沒有被使用,而是使用主鍵索引,並且此查詢正在永久。強制使用我的索引似乎也沒有幫助。

有關如何更好地索引此索引或以其他方式提高此類查詢性能的任何提示或想法?

回答

1

IN (SELECT ...)效率低於JOIN

Select a.id 
    from a 
    join b ON (a.id = b.a_id) 
    JOIN c ON b.c_id = c.id 
    where a.created >= now() - interval 90 day 
     and a.val = 0 
     and c.val = 1 

指標:

A: INDEX(val, created) -- in that order 
B: INDEX(a_id, c_id) -- in that order; "covering" 
C: Nothing new needed, assuming you have PRIMARY KEY(id) and InnoDB 

(編輯)的索引假設表將在這個順序進行:A,B,C這很可能就會因爲... A可能在WHERE中具有最好的選擇性。很明顯,B,然後C接下來。因此,我對B索引的排序。

假設A的PK是(id),那麼INDEX(val, created)INDEX(val, created, id)(如您所建議的)完全相同。

隨着一個「衍生的」表的配方中,優化器「必須」與C開始,然後轉移到B,最後,A

C: INDEX(val, id)  -- (again, `id` optional) 
B: INDEX(c_id, a_id) -- as you stated 
A: Given that it has `PRIMARY KEY(id)` and is InnoDB, no index is useful. 

由於濾波的無力上a.val的和a.created,我預測,即使這個提法將是比我慢:

Select a.id 
    FROM (SELECT id FROM C WHERE val = 1) AS cx 
    JOIN B ON b.c_id = cx.id 
    JOIN A ON (a.id = b.a_id) 
    where a.created >= now() - interval 90 day 
     and a.val = 0 

Index Cookbook。如果B是許多映射表,那麼請特別注意該主題的部分。

+0

非常感謝您的幫助。看起來優化器並不總是在同一頁面上,但它涉及到要使用哪個索引。使用這些新索引,查詢運行速度要快得多,但是我必須明確告訴它使用它們,否則它仍會嘗試使用主鍵在需要年齡的A上。 –