2013-07-23 118 views
6

在一個簡單但非常大的Innodb表上,我在列A上有一個唯一的索引,並且我想按(整數)列的順序獲得(整數)列B的列表A爲什麼MySQL Innodb在創建唯一索引時「創建排序索引」?

非常簡單的查詢,我翻閱數百萬條記錄。

SELECT B FROM hugeTable ORDER BY A LIMIT 10000 OFFSET 500000

這需要每個查詢10秒的非常快速的服務器上?

Filesort: Yes Filesort_on_disk: Yes Merge_passes: 9

這是沒有意義的我,爲何不能使用索引A?

說明顯示簡單的,沒有可能的密鑰和文件排序。

回答

10

如果B列中的值不在索引頁可用,那麼MySQL將需要訪問在基礎表的頁面。還有沒有謂詞過濾哪些行正在考慮,這意味着MySQL看到所有行都需要返回。這可以解釋爲什麼索引沒有被使用。

還要注意的是LIMIT操作都在聲明的最後處理,因爲幾乎在執行計劃中的最後一步,有一些例外。

8.2.1.3. Optimizing LIMIT Queries http://dev.mysql.com/doc/refman/5.5/en/limit-optimization.html

我懷疑你的查詢可以利用覆蓋索引,例如「ON hugetable (A,B)」,以避免排序操作。

缺席覆蓋索引,你可以嘗試重寫查詢這樣的事情,看看這是否會利用在A列的索引,並避免對數百萬行的排序操作(獲得第一個51萬行返回按順序):

SELECT i.B 
    FROM (SELECT j.A 
      FROM hugeTable j 
      ORDER 
      BY j.A 
      LIMIT 10000 OFFSET 500000 
     ) k 
    JOIN hugetable i 
    ON i.A = k.A 
ORDER 
    BY k.A 

我建議你剛上線視圖的查詢做一個EXPLAIN(別名爲K),看看它是否顯示「Using index。」

外部查詢可能還有「Using filesort」操作,但至少,這將是隻10,000行。

(注意:您可能希望在外部查詢嘗試一個 「ORDER BY i.A」 代替 「k.A」,看看是否有差別。)


附錄

不是專門針對你的問題,而是從查詢性能的角度來看,如果這是「分頁」一組行,另一個需要考慮的選項是進入「下一頁」頁面,使用「A」的值在上一個查詢中檢索到的最後一行作爲t的「起點」他下一行。

原始查詢看起來是越來越「第51頁」(每頁10,000行,第51頁將行510001通520000)。

如果你還回「A」的價值,並保持對於最後一行。爲了得到「下一步」頁面,查詢實際上可能是:

SELECT i.B, k.A 
    FROM (SELECT j.A 
      FROM hugeTable j 
      WHERE j.A > $value_of_A_from_row_520000 
     -- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 
      LIMIT 10000 
     ) k 
    JOIN hugetable i 
    ON i.A = k.A 
    ORDER 
    BY k.A 

如果您還不停的價值訴求從「第一」行,你可以利用它來進行備份頁面。這實際上只適用於前進一頁或後一頁。跳轉到不同的頁面,將不得不使用查詢的原始形式,對行進行計數。