2016-07-24 119 views
1

sql數據庫中有人類。我有這張表和過濾器形式這樣的用戶界面:enter image description here爲複雜過濾創建sql索引

我只能設置一些值(例如只有年齡和狀態)。如果未指定過濾項目,則不會將其添加到sql WHERE的條件中。 其中條件按圖片上描述的順序組合。所以,如果我想創建索引的所有情況下獲得性能提升我需要創建這個索引:

  • 名字
  • 姓氏
  • 年齡
  • 狀態
  • 生日
  • 性別
  • 名字+姓氏
  • 名字+姓氏+年齡
  • 名+姓+年齡+狀態
  • ...
  • 狀態+的生日
  • 狀態+生日+性別
  • ...
  • 狀態+性別

    它看起來對我不利。我應該只選擇最常用的組合嗎?你怎麼看?

+0

哪種RDBMS適用於?請添加一個標籤來指定您是使用'mysql','postgresql','sql-server','oracle'還是'db2' - 或者其他的東西。 –

+0

mysql/sql server – mtkachenko

+0

(1)使用標籤而不是註釋來指定供應商的細節;那就是標籤的用途,評論(假定是)是臨時的。 (2)它是什麼:MySQL或SQL Server?這些是兩個**非常不同的**引擎,在某些情況下具有顯着不同的功能。 (3)永遠不會(幾乎不會*;但實際上從不***)將*年齡*放在索引中 - 因爲它每天改變0.3%的行數,需要不斷索引重建。存儲BirthDate並根據BIrthDate和CurrentDate計算* age *查詢。 –

回答

3

如果您有索引first name + last name + age + state,則不需要first name + last name + agefirst name + last namefirst name。如果您的索引爲first name + last name + age + state,並且用戶僅在「名字」和「姓氏」上進行搜索,則數據庫將能夠使用該索引。只要用戶以相同的從左到右的順序指定列作爲索引,即使沒有指定每列,數據庫也可以使用該索引。例如,如果您有索引first name + last name + age + state並且用戶指定了「名字」和「姓氏」,那麼數據庫將能夠使用該索引跳轉到匹配的行。但是,如果用戶指定「名字」和「年齡」,或「名字」和「狀態」,那麼數據庫將只部分使用索引跳轉到具有匹配名字的行,但是它必須掃描匹配「年齡」或「狀態」的行。如果你想了解背後的技術細節,請閱讀數據庫索引和B +樹。 This是一個很好的解釋。

運行單個查詢時,數據庫也可以使用多個索引。如果你有索引

`last name` 
`state` 
`age` 

而對於「姓氏」,「狀態」,「年齡」的用戶搜索,該數據庫將能夠使用所有三個索引快速找到匹配的行的每個字段,然後將結果結合起來,並且不匹配所有三個索引的行將不會被選中。如果你看一個執行計劃,你就可以看到它這樣做。當然,這將比單個索引具有每個必需字段慢一點,但它會阻止你有很多索引。

另請注意,即使索引存在,數據庫可能不一定使用該索引,因爲執行行掃描可能會更快。例如,用上面的三個不同索引的例子,假設用戶搜索「姓氏」,「名字」和「狀態」。由於「姓氏」和「名字」的組合具有如此高的選擇性(意味着該索引中的大多數值是唯一的),因此使用索引獲取與第一個匹配的所有行可能更快名稱和姓氏,然後僅對這些行執行簡單的迭代掃描,以查找也具有匹配狀態的行,然後再使用state索引,然後加入兩個索引返回的行。

當您設計索引時,如果索引的選擇性非常低,那麼索引不會提高性能(實際上可能比進行全表掃描更糟糕)。舉例來說,性別並不是一個好的領域,因爲你只有兩個可能的價值。如果用戶僅搜索性別,則無論索引還是沒有索引,都不會獲得良好的性能,因爲您將返回一半行。

行對行,全表掃描實際上比使用索引更快。原因是當數據庫執行表掃描時,它可以直接跳到磁盤上的數據頁面。當它使用一個索引時,它必須經過幾箇中間索引頁面才能真正到達數據存儲在磁盤上的位置。對於像「性別」這樣的將要選擇一半行的字段,跟隨索引鏈接對錶中一半行的額外開銷可能超過僅使用索引掃描整個表的成本。

我會建議指標

`first name, last name` 
`birthdate` 
`state` 

如果你有搜索的頻繁領域的特定組合,那麼你可以讓該指數也加快速度。但是,不要爲每個字段組合建立索引。

如果您使用「生日」而不是「生日」,那麼您不需要「年齡」,因爲您可以根據「生日」計算出來,然後對「生日」進行between查詢。如果你不得不爲「生日」和「年齡」分開列,那麼你也可以索引「年齡」。但是,像其他用戶在下面評論的那樣,您必須不斷更新您的年齡。我強烈建議不要這種設計。

要考慮的最後一件事是是否試圖使覆蓋索引。覆蓋索引是用戶搜索的每個字段都是索引的一部分。例如,假設您的表格中有100個字段,但用戶通常只會根據姓名查找某人的狀態和年齡。所以,你的查詢有很大比例是這個樣子

SELECT STATE, AGE FROM PEOPLE WHERE FIRSTNAME = 'Homer' AND LASTNAME = 'Simpson' 

如果你的指數是LASTNAME, FIRSTNAME,則數據庫將查找「荷馬史詩」和「辛普森」的索引(這將涉及讀取從幾個索引頁磁盤)中,使用索引指針轉到存儲數據記錄的磁盤頁面,讀取整個數據頁面,將其解析爲字段,然後返回狀態和年齡。

現在,假設您運行相同的查詢,但您的索引爲LASTNAME, FIRSTNAME, STATE, AGE。數據庫引擎仍會使用您的索引查找「Homer」和「Simpson」,但一旦找到合適的索引記錄(與上面的工作方式完全相同),該索引記錄已經有STATEAGE。因此,數據庫可以直接從索引中獲得查詢結果,而不必從磁盤讀取數據頁面。

在表掃描的情況下,覆蓋指數可以顯着提高性能的情況。假設你的表中有100個字段(所以一行的大小是幾百字節或更多)。現在,用戶運行查詢

SELECT FIRSTNAME, LASTNAME, AGE FROM PEOPLE 

數據庫必須讀取整個表(包括所有100個字段這是沒有必要爲此查詢)來獲得結果。如果您有索引LASTNAME, FIRSTNAME, AGE,那麼數據庫可以通過掃描整個索引而不是掃描整個表來獲取結果。由於在這種情況下,單個索引元素比單個數據行在字節方面小得多,所以查詢將快得多。

在您的表中有這麼幾個字段的特定情況下,由於索引中的字段與表中的字段相同,所以覆蓋索引可能不會非常有用,從而破壞了整個目的。但是,對於包含數十個字段的表(其中只有少數幾個字段通常被查詢),覆蓋索引可能是加快查詢速度的好方法。

+0

一個非常好的解釋;比當前發佈的其他兩個更好。 *覆蓋索引*的快速描述是我能想到的,可能有用地添加。 –

+1

好的建議。我會補充一點。 –

+1

「數據庫在運行單個查詢時也可以使用多個索引」 - 對於某些數據庫或某些類型的索引,這可能是正確的,但對於所有類型的RDBMS通常都不是這樣。 – APC

-1

我會去用這種方法..

上有一個索引鍵列是偉大的濾除行和做一個尋求exactly.But與你的表格,你需要多鍵作爲鍵列,但有很多關鍵列是不好的,它也有一個極限..

因此,我建議你確定幾個列是獨特的或複合索引與字段不會是空的,如果你沒有獨特的列,並創建一個聚集索引..

我會創建clust生日ERED指數,年齡(只是一個想法,你可以使用其他列也一樣),然後創建一個默認的參數,如下面的存儲過程..

create proc usp_getformdata 
(
@firstname varchar(200)= null, 
@lastname varchar(200)=null, 
@age int=null, 
@state varchar(20)=null, 
@birthday datetime =null, 
@gender varchar(10)=null 
) 
As 
Begin 
select 
* from 
yourtable 
where 
[email protected] 
and 
[email protected] 

--do for all columns 
End 
-1

一個指數可連續工作多where條款。所以:

(firstname, lastname, age, state) 

作品where條款具有平等的條件:

firstname 
firstname & lastname 
firstname & lastname & age 
firstname & lastname & age & state 

我建議你建立了一套指標,爲常見的情況 - 三個或四個指標。將多個鍵添加到索引中,以便用於更多和更精確的搜索。不要打擾將低基數值(例如gender)作爲索引中的第一個鍵,因爲只使用性別過濾器的查詢可能需要全表掃描。

如果這不符合您的需求,您可能需要考慮訪問數據的其他方法,例如全文索引。

+0

年齡是一個可怕的屬性放在任何指數 - 因爲它每天更改0.3%的索引過時的所有記錄。出生日期很好,但任何年齡的過濾器都必須根據當前日期與出生日期的比較細化爲過濾器。 –

2

大量的索引是一個'壞'的想法。
單個列上的索引不會有太大幫助。
作爲另一個「前綴」的索引是多餘的。
將不會使用低'基數'(例如gender)標誌或列上的索引。

建議:每列開始一個索引。然後將第二列添加到每個索引。根據可能一起測試的內容挑選第二列。避免同時使用(a,b)(b,a)

然後查看「真實」用戶生成哪些類型的查詢。相應地調整索引列表。這個信息可能會導致一些3列索引。