2009-07-07 111 views
9

假設我有一個數據庫表,列a,b和c。我打算對所有三列進行查詢,但我不確定我查詢的是哪些列。有一個在一個索引極大加快了搜索的表足夠的行,但感覺不對的可能指標的所有排列(像這樣):有沒有更好的方法來索引多列而不是爲每個排列創建一個索引?

a 
b 
c 
a, b 
a, c 
b, c 
a, b, c 

有沒有更好的方式來處理這個問題? (這很可能我只是很好地索引a,b,c,因爲這會很快減少行數,但是我想知道是否有更好的方法。)

如果您需要在實際數據中,更具體的例子是城市,州和郵政編碼。另外,我正在使用MySQL數據庫。

回答

19

在MS SQL中,索引「a,b,c」將覆蓋您的場景「a」; 「a,b」;和「a,b,c」。所以你只需要以下索引:

a, b, c 
b, c 
c 

不知道MySQL是否以相同的方式工作,但我會這樣認爲。

+7

這是正確的答案。 MySQL的工作方式相同,這種技術被稱爲「最左前綴」。從http://dev.mysql.com/doc/refman/5.0/en/mysql-indexes.html上的MySQL手冊:「如果表有多列索引,索引的任何最左邊的前綴都可以使用例如,如果您在(col1,col2,col3)上有三列索引,則您在(col1),(col1,col2)和(col1,col2,col3)上具有索引搜索功能, 「 – zombat 2009-07-07 03:20:32

+0

嗯,我應該知道這一點。 ;)非常棒,我會給這個鏡頭。 – 2009-07-07 03:28:26

+1

您可能還需要a,c,但這取決於您的查詢的樣子。您可能還需要單獨的索引來涵蓋Andriyev提到的OR情景,不確定。 – 2009-07-07 03:38:36

1

您創建的索引越多,在更新和刪除操作期間您的性能就會越高。因爲索引本身可能會更新。

是的,您可以使用多列索引。像

CREATE TABLE temp (
    id   INT NOT NULL, 
    a   INT NULL, 
    b   INT NULL, 
    c   INT NULL, 
    PRIMARY KEY (id), 
    INDEX ind1 (a,b,c), 
    INDEX ind2 (a,b) 
); 

某事,這類型的索引即IND1一定會幫你查詢,如

SELECT * FROM temp WHERE a=2 AND b=3 AND c=4; 

同樣,IND2將幫助您查詢,如

SELECT * FROM temp WHERE a=2 AND b=3; 

但這些指標榮獲」如果查詢有點像

SELECT * FROM temp WHERE a=2 OR b=3 OR c=4; 

在這裏,您需要單獨的a,b和c索引。

因此,我不會同意John所說的那樣,即在a,b,c上有索引,如果您覺得您的工作負載涵蓋更多的多列查詢,那麼您可以切換到多列索引。

歡呼

1

鑑於您的列實際上是城市,州和郵編,我只想建議如下指標:

INDEX(郵編)

如果我是正確的,郵編這些代碼在美國並不重複,所以向索引添加城市或州信息毫無意義,因爲它們對於所有郵政編碼都是相同的值。例如,90210總是洛杉磯,CA.

INDEX(市(5))INDEX(市(5)),州)

這僅僅是城市的名字的前五個字母索引。在很多情況下,這將具有足夠的特徵,使0123,索引不會提供任何有用的過濾。例如,'洛杉磯A'幾乎肯定是來自洛杉磯的記錄。也許在美國還有另一個以'洛杉磯A'開頭的小鎮,但是將會有這麼幾條記錄,它不值得用國家數據混淆這個指數。另一方面,一些城市的名字出現在許多州(斯普林菲爾德想到),所以在這種情況下,最好也要將州列入索引。你需要弄清楚哪一個索引最適合你的數據集。如果有疑問,我會選擇第二個指數(城市和州)。

INDEX(國家,sort_field

國家是一個非常寬泛的指數(很可能是紐約,獨自CA將有記錄的30%)。如果您計劃顯示這個信息給用戶,比方說,30所記錄的時間,那麼你就必須在

... WHERE STATE = "NY" 
ORDER BY <sort_field> 
LIMIT <number>, 30 

結束了查詢,以查詢效率,你需要包括在排序列國家指數。因此,如果您顯示按姓氏排序的頁面(假設您有該列),那麼您將使用INDEX(State,LastName(3)),否則MySQL必須對'NY'記錄的所有進行排序它可以給你你想要的30。

1

這取決於你的sql查詢。

指數(A,B,C)是不同於指數(B,C,A)指數(A,C,B)

4

要爲所有可能的等同條件使用索引在N列,則需要C([N/2], N)指標,即N!/([N/2]! * (N - [N/2])!)

看到這篇文章在我的博客進行詳細的解釋:

您還可以通過俄羅斯數學家Egor Timoshenko讀嚴格的數學proof

指數合併

如果列col1col2col3是有選擇性的,那麼這個查詢

SELECT * 
FROM mytable 
WHERE col1 = :value1 
     AND col2 = :value2 
     AND col3 = :value3 

一個也可以,但是,使用下列技術得到較少的指標不俗的表現

可以在col1col2col3上使用三個單獨的索引,選擇單獨匹配每一個條件,即ROWID的和他們找到它們的交集,就像:

SELECT * 
FROM (
     SELECT rowid 
     FROM mytable 
     WHERE col1 = :value1 
     INTERSECT 
     SELECT rowid 
     FROM mytable 
     WHERE col2 = :value2 
     INTERSECT 
     SELECT rowid 
     FROM mytable 
     WHERE col3 = :value3 
     ) mo 
JOIN mytable mi 
ON  mi.rowid = mo.rowid 

位圖索引

PostgreSQL可以在查詢過程中正確建立在內存中的臨時位圖索引。

位圖索引是相當緊湊的連續位數組。

爲數組設置的每個位都指示應該從表中選擇相應的tid

對於具有1G行的表,這種索引可以採用臨時存儲的128M

以下查詢:

SELECT * 
FROM mytable 
WHERE col1 = :value1 
     AND col2 = :value2 
     AND col3 = :value3 

將首先分配一個零填充的位圖足夠大以覆蓋所有可能的tid'表中的S(即大到足以採取一切tid的從(0, 0)到最後tid,沒有考慮到丟失tid的問題)。

然後它會尋找第一個索引,如果它們滿足第一個條件,則將這些位設置爲1

然後它將掃描第二個索引AND'滿足第二個條件的位爲1。只有那些滿足這兩個條件的位纔會有1

第三個索引相同。

最後,它將只選擇tid對應於設置的位的行。

tid的將被依次取出,所以它非常有效。

相關問題