2017-04-24 26 views
0

有一個10+億表有三列所需的索引:onetwothree和SQL查詢類似SELECT * FROM table ORDER BY one, two, three LIMIT 1 - 我真的需要創建使用所有三列的多列索引?MySQL的:對於多列排序

我知道肯定的是,如果onetwo匹配,最多有10行,不同的three

快速選擇是否夠用? -

CREATE INDEX MY_INDEX ON table (one, two);

回答

1

隨着INDEX(one, two, three),查詢將直接下降到BTree到一個(LIMIT 1)所需的行。

隨着INDEX(one, two),查詢會直降B樹的第一個這樣的行,然後掃描前進的先進的10排,將其保存到TMP表,對它們進行排序(ORDER BY包括three)(可能是在做記憶),並提供第一個。雖然這聽起來更復雜,但它不會(在這個例子中)慢得多。

它不會是「表掃描」(「ALL」),但可能是「範圍」掃描。使用EXPLAIN SELECT ...來查看。

如果three是一個龐大的字符串,那麼3-col索引將是體積較大的;這對磁盤空間和性能有一定的影響。

如果您只需要(one, two)進行其他查詢,那麼索引的工作合理(除非是「龐大」的評論)。

如果你這樣做SELECT one, two, three FROM ...,3部分指數會更好,因爲它將「覆蓋」。 SELECT *不會有這樣的獎金。

底線:任何一個指數都是「OK」,還有很多其他因素,這使得很難確定該做什麼。

0

你可能會認爲MySQL是很聰明,最多隻使用索引中的前10行讀取,然後排序這些。不幸的是,它不是(因爲優化器此時不考慮limit)。您可以使用explain select ...驗證,它會顯示MySQL將執行全表掃描("ALL")。

documentation描述的條件,以便能夠使用索引來優化order by

索引也可以即使ORDER BY不索引完全匹配所使用的,只要所有未使用的部分索引和所有額外的ORDER BY列是WHERE子句中的常量。

您的第三欄不滿足此條件。所以這個查詢不會使用這個索引(這並不意味着它可能對其他東西不是有用的)。

由於MySQL 5.6,但是有所謂的filesort priority queue optimization來容納limit:雖然MySQL仍然會讀整個表,它不會整個表排序(這將是一個耗時的過程),但會停止當它知道第一行會是什麼時,這會讓你的查詢很快被接受。

但是你可以重寫查詢到你所想的正是:

SELECT * FROM 
    (select * from table ORDER BY one, two LIMIT 10) sub 
order by one, two, three limit 1; 

這將讀取使用該索引中的第10行,然後就它們排序。當然,如果你完全確信你最多隻有10行,它當然只能正常工作。

通過知道可能行數的最大值來獨立優化查詢的更一般的方法是,例如,

SELECT * FROM table 
where one = (select min(one) from table) 
order by one, two, three limit 1; 

這將使用索引來減少必須通過查找最低值one第一(使用索引),並只考慮這些行進行讀取和filesorted的行數。您可以同樣包含two的條件。

或者你可以簡單地在你的索引中使用所有三列(儘管取決於你的第三列的大小,這是不合理的)。這種優化往往會在一點上趕上。如果你使用第一種方法,並在2年內將有11行可能,你(或你的繼任者)將不得不記住你在你的代碼中有這個隱含的條件。

+0

我反駁了「表掃描」的說法。 –