SQL Server索引設計 <第五篇>

SQL Server索引的設計主要考慮因素以下:算法

  檢查WHERE條件和鏈接條件列;數據庫

  使用窄索引;緩存

  檢查列的選擇性;函數

  檢查列的數據類型;性能

  考慮列順序;學習

  考慮索引類型(彙集索引OR非彙集索引);測試

1、檢查WHERE條件列和連接條件列                                                                             

  當一個查詢提交到SQL Server時,查詢優化器嘗試爲查詢中引用的全部表查找最佳的數據訪問機制。下面列出查詢優化器針對WHERE和鏈接的工做方式:大數據

  1. 優化器識別WHERE子句和鏈接條件中包含的列。
  2. 接着優化器檢查這些列上的索引。
  3. 優化器經過從索引上維護的統計肯定子句的選擇性,評估每一個索引的有效性。
  4. 最終,優化器根據前面幾個步驟中手機的信息,估計讀取所限定行開銷最低的方法。

  爲了理解WHERE子句在查詢中的重要性,來考慮一個示例。優化

  SELECT * FROM Person WHERE Id = 100;

  假設上面的表Id列爲彙集索引。上面的語句有了WHERE子句,查詢優化器將檢查WHERE子句的列Id,肯定Id列上有彙集索引,從彙集索引上的統計評估WHERE子句的高選擇性,而且決定使用這個索引。spa

  查詢優化器的表現說明,WHERE子句列幫助優化器選擇一個對查詢最優的索引操做。這也適用於兩個表之間的鏈接條件中使用的列。優化器查找到WHERE子句或鏈接條件列上的索引,若是可用,考慮使用該索引來從表中檢索行。查詢優化器在執行一個查詢時,考慮WHERE子句或鏈接條件列上的索引。所以WHERE子句或鏈接條件中頻繁使用的列上有索引將幫助優化器避免基本表的掃描。

  可是,當一個表中的數據總量很是小以致於能夠放入一個數據頁,那麼表掃描可能比索引查找更快,若是有一個好的索引,可是仍然進行掃描,能夠考慮這個問題。

2、使用窄索引                                                                                                             

  能夠在表中的一個列組合上建立索引,可是爲了最好的性能,儘可能在索引中使用較少的列。還應該避免在索引中使用寬數據類型的列。

  •   窄索引:索引中的列數儘量少;
  •   寬數據類型:佔用空間比較大的數據類型,如:CHAR、VARCHAR、NVARCHAR、CLOB等。除非絕對必須,不然在索引中要把大尺寸的寬數據類型的列的使用降到最少。

  窄索引能夠在8KB的索引頁面上容納比寬索引更多的行,這將有以下優勢:

  1. 減小I/O數量(讀取更少的8KB頁面);
  2. 使數據庫緩存更有效,由於SQL Server能夠緩存更少的索引頁面,從而減小內存中的索引頁面所需的邏輯讀操做;
  3. 減小數據庫存儲空間;

   下面之後一個示例來講明窄索引的好處:

  第一次,咱們的索引僅僅包含Name列:

   

  第二次,咱們的索引INCLUDE多了兩列:

  

  咱們看到。包含多了兩個列以後,邏輯讀取比一個列多?爲何呢?由於包含多了兩個列,索引須要佔用更大的空間,一個數據頁放的索引行少了,就須要讀取更多的數據頁。

3、索引列的選擇性                                                                                                      

  索引,特別是非彙集索引,主要在索引中有至關高級別的選擇性的狀況下是有益的。所謂選擇性,指的是列中惟一值的百分比。列中的惟一值百分比越高,選擇性就越高,從而索引的溢出就越大。若是一個表中有2000條記錄,表索引列有1990個不一樣的值,那麼這個索引的選擇性就是1980/2000=0.99。

  在前面的學習中已經瞭解到,在非彙集索引中的查詢實際上只是開始。要找到真正的數據,仍須要對彙集索引再執行一次循環遍歷。甚至使用堆上的非彙集索引,仍然須要執行多個單獨的物理讀操做。

  若是在非彙集索引中的一個查找將要在彙集索引上產生多個額外的查找,那麼進行表掃描可能更好。這裏可能產生的影響其實是很是驚人的。若是被索引的列惟一性達不到90%~95%,那麼考慮由非彙集索引建立的循環過程是不值得的。好比一個性別選項,設置爲了bit,而後建索引。查詢優化器是不會考慮使用這種索引的。

  由以上的分析,可知主鍵的選擇性是100%,選擇性越接近主鍵,建在該列的索引的效率就會越高。

  索引的可選擇性是衡量索引的利用率的方法,好比在極端的狀況下,一個表記錄數是1000,而索引列的值只有5個不一樣的值,則索引的可選擇性不好(只有0.005)。這樣的情形使用全表掃描要比採用索引還好。

  下面來實操下,計算下索引的選擇性,固然測試表數據小,可能查詢時即便有了索引,SQLServer也未必會用。

  

  由以上信息可計算獲得對fdkeyname列的索引選擇性爲

  110/119 = 0.924

  這樣仍是麻煩啊?難道手工算嗎?下面給出一條SQL語句查出選擇性的方法:

SELECT CAST(count(DISTINCT fdkeyname) AS FLOAT) / CAST(count(*) AS FLOAT)
FROM JM_Keyword;

  

  選擇性規則的一個例外與外鍵有關,若是表中有一列是外鍵,那麼在該列上有一個索引,這極可能是有益的。爲何是外鍵而不是其餘列呢?外鍵經常是與它們引用的錶鏈接的目標。無論選擇性如何,索引在鏈接性能方面是很是有幫助的,由於它們容許合併鏈接。合併鏈接從每一個表中獲取一行進行比較,查看它們是否和鏈接條件匹配。由於兩個表中的相關列上都存在索引,因此對兩個行的查找是很是快的。

  下面以一個示例來講明問題:

  我在一個Person表中的性別列創建了一個索引,而後來查看查詢優化器的查詢方式:

  

  爲何查詢優化器不選擇從Gender列的索引來查找數據呢?

  我要返回前10條性別爲"男"數據,若是使用索引,咱們知道這個Gender列上的索引的選擇性大約爲50%。SQL Server即便經過索引找到了前10條性別爲男的彙集列,也還要再經過Id到彙集索引中去查找數據,這樣還不如直接掃描彙集錶快。所以SQL Server的查詢優化器忽略了這個索引。

  經過WITH INDEX(索引名)能夠強制使用索引查找,下面給出這兩種查詢方式的讀取次數比較:

  強制索引方式讀取:

  

  查詢優化器選擇讀取:

  

  由上面咱們能夠看到,強制使用索引的話,邏輯讀取高,可是預讀少。咱們知道預讀是與分析並行執行,並且可以載入緩存中的。從SQL Server的選擇來看,基本上能夠得出一個結論,邏輯讀比預讀更加佔用時間。

4、檢查索引的數據類型                                                                                              

  索引列的數據類型也是很重要的。例如,在一個整數鍵值上的索引查詢是很是快的,這是由於int數據類型的尺寸很小,並且算數操縱很容易。也可使用int數據的其餘變種(bigint,smallint,tinyint)做爲索引列,而字符串數據類型(char、varchar、nchar、ncarchar、)須要字符串匹配操做,這一般比整數匹配操做的開銷更大。

   假設但願在一列上建立索引但卻有兩個候選列,一個是int數據類型,一個是char(4)數據類型。這兩種數據類型在SQL Server 2008中大小都是4字節,可是仍然應該首選int數據類型做爲索引。由於char(4)數據類型中的值1實際上保存爲1後面跟着3個空格,4個字節組合是0x3五、0x20、0x20、0x20。CPU不理解如何在這個數據上執行算數運算。所以在算數操做以前要將其轉換爲一個整數,而在int數據類型中,值1被保存爲0x00000001。CPU能夠簡單地在這個數據上執行算數運算。

5、索引列順序                                                                                                           

  索引鍵值在索引的第一列上排序,而後再一次再下一列中排序。

  假設咱們的在一張表中創建一個複合索引:

  CREATE NONCLUSTERED INDEX indexName ON Table(c1,c2) 

  那麼索引中的數據大概以下:

c1 c2
1 1
1 2
2 1
2 2
3 1
3 2
   假設大部分在上表上的查詢與下面的語句相似
  SELECT * FROM Table WHERE c1 = 1 或 2   SELECT * FROM Table WHERE c2 = 1 或 2 AND c1 = 1 或 2

  (c2,c1)對上面兩個查詢都有利,可是(c1,c2)上的索引就不合適,由於它首先在c1上排序,而第一個SQL語句須要在c2上排序。

  這就比如使用電話本。全部項都是按先姓後名的方式進行索引-若是值知道要通電話的人的名是「備」,那麼這種排列順序不能帶來什麼好處。另外一方面,若是隻知道他的姓是「劉」,那麼索引將能夠用來縮小查找範圍。

6、考慮索引類型                                                                                                         

  考慮索引的類型 SQL Server中有兩種主要的索引類型:彙集索引和非彙集索引。這兩種類型都爲B-樹結構。二者之間的主要區別是彙集索引中的葉子頁是表的數據。所以表中的數據和彙集索引的順序相同,這意味着,彙集索引就是該表。在決定使用索引類型時,兩種索引類型的葉子級別上的差異變得很是重要。

  一個表只有一個彙集索引,應該明智地選擇它。

  SQLServer在默認狀況下,主鍵和彙集索引是一塊兒建立的。若是不想將主鍵聲明爲彙集索引,那麼在建立表時,只需添加NONCLUSTERED關鍵字。

CREATE TABLE MyTableKeyExample {   Column1 int IDENTITY     PRIMARY KEY NONCLUSTERED,   Column2 int }

  一旦建立了索引,改變它的惟一方法是刪除和重建它,因此須要一開始就作對。

  若是改變了彙集索引所在的列,那麼SQL Server將須要對整個表徹底從新排序(由於對於彙集索引,表的排列順序和索引順序是相同的)。

  對於數據比較多的表,改變彙集索引,須要從新排序的數據很是多,要從如下幾個方面進行考慮。

  它將須要花費多長時間。   是否有足夠的空間?爲了在彙集索引上執行從新排序,額外須要的平均空間量將爲表已經佔用空間量的1.2倍。確保有足夠的空間來操做。   應當使用SORT_IN_TEMPDB選項嗎?若是tempdb位於與主數據庫不一樣的物理陣列上,而且它有足夠的空間,那麼答案是確定的。

  一、正面觀點

  若是列常做爲範圍查詢的對象,那麼彙集索引對這類查詢是頗有用的。這類查詢一般使用between語句或<or>符號。使用GROUP BY以及利用MAX、MIN和COUNT聚合函數的查詢也是使用範圍和偏好彙集索引的查詢的重要示例。彙集索引適合用於此處,是由於搜索能夠直接到達物理數據中的特定點,可一直讀數據,直到範圍的末端,而後中止。這種方法很是有效。當想要數據基於彙集鍵排序(ORDER BY),彙集也是極好的方法。

  二、反面觀點

  有兩種狀況下,你可能不想建立彙集索引。

  (1)、當有更好的位置來使用它時。不要由於列看上去適合作彙集索引就將它用做彙集索引(主鍵是最多見的罪魁禍首)-要肯定沒有更合適的其餘列。

  (2)、在將要以非連續的順序進行大量插入時。這會進行頁拆分,而且會消耗大量時間。

  例如,一個交易系統,用

  ARXXXX

  GLXXXX

  APXXXX

  做爲主鍵,並使用默認的彙集索引,那麼在插入數據的時候,常常會發生頁拆分。由於數據會按照彙集索引進行排序,那麼不停的錄入數據,就可能會常常性地發生頁拆分,引發短暫停頓。

  幸運的是,有一些方法能夠避免以上情形:

  選擇在插入時是連續的彙集鍵。能夠以此建立一個標識列,或者也可使用另外一個列,該列對於任何輸入交易來講,在邏輯上都是連續的。

  選擇不在這個表上使用匯集索引。對於相似的這裏的情形來講,這一般是最好的選擇,由於在對上非彙集索引中的插入通常比在彙集鍵上的插入更快。  

  什麼時候應該使用匯集索引與非彙集索引

動做描述        使用匯集索引      使用非彙集索引

列常常被分組排序    應           應

返回某範圍內的數據   應           不該

一個或極少不一樣值    不該          不該

小數目的不一樣值     應           不該

大數目的不一樣值       不該          應

頻繁更新的列      不該          應

外鍵列         應           應

主鍵列         應           應

頻繁修改索引列     不該          應

  事實上,咱們能夠經過前面彙集索引和非彙集索引的定義的例子來理解上表。如:返回某範圍內的數據一項。好比你的某個表有一個時間列,剛好您把聚合索引創建在了該列,這時你查詢2010年1月1日到2013年1月1日之間的所有數據時,這個速度就將是很快的,由於你的這本字段正文是按日期進行排序的,彙集索引只須要找到要檢索的全部數據中的開頭和結尾數據便可;而不像非彙集索引,必須先查到目錄中查到每一項數據對應的頁碼,而後再根據頁碼查到具體內容。

  三、結合實際,談索引使用的誤區

下面列出在實踐中的一些誤區:

一、主鍵就是索引

  這種想法是極端錯誤的,是對彙集索引的一種浪費。雖然SQL SERVER默認是在竹簡上簡歷彙集索引的。一般,咱們會在每一個表都創建一個Id列,以區分每條數據,而且這個Id列是自動增大的,增加量一半設爲1。以一個辦公自動化的紫銅爲例子。若是將Id列設爲主鍵,SQL SERVER會將此列默認爲彙集索引,這樣作有好處,就是可讓你的數據在數據庫中按照Id進行物理排序,但這樣作的意義不大。彙集索引的速優點是很是明顯的,而每一個表中只能有一個彙集索引的規則,這使得彙集索引變得更加珍貴。

  從咱們前面談到的彙集索引的定義咱們能夠看出,使用匯集索引的最大好處就是可以根據查詢要求,迅速縮小查詢範圍,避免全表掃描。在實際應用中,由於Id號是自動生成的,咱們並不知道每條記錄的Id號,因此咱們很難在時間中用Id號來進行查詢。這個主鍵做爲彙集索引成爲一種資源浪費。其次,讓每一個ID號都不一樣的字段做爲彙集索引也不符合「大數目的不一樣值狀況下不該創建聚合索引」規則;固然,這種狀況只是針對用戶常常修改記錄內容,特別是索引項的時候會負做用,但對於查詢速度並無影響。在辦公自動化系統中,不管是系統首頁顯示的須要用戶簽收的文件、會議仍是用戶進行文件查詢等任何狀況下進行數據查詢都離不開字段的是「日期」還有用戶自己的「用戶名」。

  一般,辦公自動化的首頁會顯示每一個用戶還沒有簽收的文件或會議。雖然咱們的where語句能夠僅僅限制當前用戶還沒有簽收的狀況,但若是您的系統已創建了很長時間,而且數據量很大,那麼,每次每一個用戶打開首頁的時候都進行一次全表掃描,這樣作意義是不大的,絕大多數的用戶1個月前的文件都已經瀏覽過了,這樣作只能徒增數據庫的開銷而已。事實上,咱們徹底可讓用戶打開系統首頁時,數據庫僅僅查詢這個用戶近3個月來未閱覽的文件,經過「日期」這個字段來限制表掃描,提升查詢速度。若是您的辦公自動化系統已經創建的2年,那麼您的首頁顯示速度理論上將是原來速度8倍,甚至更快。 
在這裏之因此提到「 理論上」三字,是由於若是您的彙集索引仍是盲目地建在ID這個主鍵上時,您的查詢速度是沒有這麼高的,即便您在「日期」這個字段上創建的索引(非聚合索引)。下面咱們就來看一下在1000萬條數據量的狀況下各類查詢的速度表現(3個月內的數據爲25萬條):    (1)僅在主鍵上創建彙集索引,而且不劃分時間段:

Select gid,fariqi,neibuyonghu,title from tgongwen 

  用時:128470毫秒(即:128秒)    (2)在主鍵上創建彙集索引,在fariq上創建非彙集索引:

select gid,fariqi,neibuyonghu,title from Tgongwen 
where fariqi> dateadd(day,-90,getdate()) 

  用時:53763毫秒(54秒)    (3)將聚合索引創建在日期列(fariqi)上:

select gid,fariqi,neibuyonghu,title from Tgongwen 
where fariqi> dateadd(day,-90,getdate()) 

用時:2423毫秒(2秒) 
雖然每條語句提取出來的都是25萬條數據,各類狀況的差別倒是巨大的,特別是將彙集索引創建在日期列時的差別。事實上,若是您的數據庫真的有1000萬容量的話,把主鍵創建

在ID列上,就像以上的第一、2種狀況,在網頁上的表現就是超時,根本就沒法顯示。這也是我摒棄ID列做爲彙集索引的一個最重要的因素。 
得出以上速度的方法是:在各個select語句前加:declare @d datetime  set @d=getdate() 
並在select語句後加:  select [語句執行花費時間(毫秒)]=datediff(ms,@d,getdate())

二、只要創建索引就能顯著提升查詢速度

  事實上,咱們能夠發現上面的例子中,第二、3條語句徹底相同,且創建索引的字段也相同;不一樣的僅是前者在fariqi字段上創建的是非聚合索引,後者在此字段上創建的是聚合索引,但查詢速度卻有着天壤之別。因此,並不是是在任何字段上簡單地創建索引就能提升查詢速度。從建表的語句中,咱們能夠看到這個有着1000萬數據的表中fariqi字段有5003個不一樣記錄。在此字段上創建聚合索引是再合適不過了。在現實中,咱們天天都會發幾個文件,這幾個文件的發文日期就相同,這徹底符合創建彙集索引要求的:「既不能絕大多數都相同,又不能只有極少數相同」的規則。由此看來,咱們創建「適當」的聚合索引對於咱們提升查詢速度是很是重要的。 事實上,咱們能夠發現上面的例子中,第二、3條語句徹底相同,且創建索引的字段也相同;不一樣的僅是前者在fariqi字段上創建的是非聚合索引,後者在此字段上創建的是聚合索引,但查詢速度卻有着天壤之別。因此,並不是是在任何字段上簡單地創建索引就能提升查詢速度。從建表的語句中,咱們能夠看到這個有着1000萬數據的表中fariqi字段有5003個不一樣記錄。在此字段上創建聚合索引是再合適不過了。在現實中,咱們天天都會發幾個文件,這幾個文件的發文日期就相同,這徹底符合創建彙集索引要求的:「既不能絕大多數都相同,又不能只有極少數相同」的規則。由此看來,咱們創建「適當」的聚合索引對於咱們提升查詢速度是很是重要的。

三、把全部須要提升查詢速度的字段都加進彙集索引,以提升查詢速度

  上面已經談到:在進行數據查詢時都離不開字段的是「日期」還有用戶自己的「用戶名」。既然這兩個字段都是如此的重要,咱們能夠把他們合併起來,創建一個複合索引(compound index)。    

    不少人認爲只要把任何字段加進彙集索引,就能提升查詢速度,也有人感到迷惑:若是把複合的彙集索引字段分開查詢,那麼查詢速度會減慢嗎?帶着這個問題,咱們來看一下如下的查詢速度(結果集都是25萬條數據):(日期列fariqi首先排在複合彙集索引的起始列,用戶名neibuyonghu排在後列)

(1)select gid,fariqi,neibuyonghu,title from Tgongwen where fariqi>'2004-5-5' 

  查詢速度:2513毫秒

(2)select gid,fariqi,neibuyonghu,title from Tgongwen where fariqi>'2004-5-5' and neibuyonghu='辦公室' 

  查詢速度:2516毫秒

(3)select gid,fariqi,neibuyonghu,title from Tgongwen where neibuyonghu='辦公室'

  查詢速度:60280毫秒

  從以上試驗中,咱們能夠看到若是僅用匯集索引的起始列做爲查詢條件和同時用到複合彙集索引的所有列的查詢速度是幾乎同樣的,甚至比用上所有的複合索引列還要略快(在查詢結果集數目同樣的狀況下);而若是僅用複合彙集索引的非起始列做爲查詢條件的話,這個索引是不起任何做用的。固然,語句一、2的查詢速度同樣是由於查詢的條目數同樣,若是複合索引的全部列都用上,並且查詢結果少的話,這樣就會造成「索引覆蓋」,於是性能能夠達到最優。同時,請記住:不管您是否常用聚合索引的其餘列,但其前導列必定要是使用最頻繁的列。 

其餘書上沒有的索引使用經驗總結  一、用聚合索引比用不是聚合索引的主鍵速度快  下面是實例語句:(都是提取25萬條數據)

select gid,fariqi,neibuyonghu,reader,title from Tgongwen where fariqi='2004-9-16' 

  使用時間:3326毫秒

select gid,fariqi,neibuyonghu,reader,title from Tgongwen where gid<=250000 

  使用時間:4470毫秒  這裏,用聚合索引比用不是聚合索引的主鍵速度快了近1/4。 
二、用聚合索引列比用通常的主鍵做order by時速度快,特別是在小數據量狀況下

select gid,fariqi,neibuyonghu,reader,title from Tgongwen order by fariqi 

  用時:12936

select gid,fariqi,neibuyonghu,reader,title from Tgongwen order by gid 

  用時:18843 
  這裏,用聚合索引比用通常的主鍵做order by時,速度快了3/10。事實上,若是數據量很小的話,用匯集索引做爲排序列要比使用非彙集索引速度快得明顯的多;而數據量若是很大的話,如10萬以上,則兩者的速度差異不明顯。

三、使用聚合索引列內的時間段,搜索時間會按數據佔整個數據表的百分比成比例減小,而不管聚合索引使用了多少個

select gid,fariqi,neibuyonghu,reader,title from Tgongwen where fariqi>'2004-1-1' 

  用時:6343毫秒(提取100萬條)

select gid,fariqi,neibuyonghu,reader,title from Tgongwen where fariqi>'2004-6-6' 

  用時:3170毫秒(提取50萬條)

select gid,fariqi,neibuyonghu,reader,title from Tgongwen where fariqi='2004-9-16' 

  用時:3326毫秒(和上句的結果如出一轍。若是採集的數量同樣,那麼用大於號和等於號是同樣的)

select gid,fariqi,neibuyonghu,reader,title from Tgongwen where fariqi>'2004-1-1' and fariqi<'2004-6-6' 

  用時:3280毫秒 
4 、日期列不會由於有分秒的輸入而減慢查詢速度 
下面的例子中,共有100萬條數據,2004年1月1日之後的數據有50萬條,但只有兩個不一樣的日期,日期精確到日;以前有數據50萬條,有5000個不一樣的日期,日期精確到秒。

select gid,fariqi,neibuyonghu,reader,title from Tgongwen where fariqi>'2004-1-1' order by fariqi 

  用時:6390毫秒

select gid,fariqi,neibuyonghu,reader,title from Tgongwen where fariqi<'2004-1-1' order by fariqi 

  用時:6453毫秒 

五、其餘注意事項    「水可載舟,亦可覆舟」,索引也同樣。索引有助於提升檢索性能,但過多或不當的索引也會致使系統低效。由於用戶在表中每加進一個索引,數據庫就要作更多的工做。過多的索引甚至會致使索引碎片。    

因此說,咱們要創建一個「適當」的索引體系,特別是對聚合索引的建立,更應精益求精,以使您的數據庫能獲得高性能的發揮。    

固然,在實踐中,做爲一個盡職的數據庫管理員,您還要多測試一些方案,找出哪一種方案效率最高、最爲有效。

6、彙集索引的重要性和如何選擇彙集索引

  在上一節的標題中,筆者寫的是:實現小數據量和海量數據的通用分頁顯示存儲過程。這是由於在將本存儲過程應用於「辦公自動化」系統的實踐中時,筆者發現這第三種存儲過程在小數據量的狀況下,有以下現象: 
一、分頁速度通常維持在1秒和3秒之間。 
二、在查詢最後一頁時,速度通常爲5秒至8秒,哪怕分頁總數只有3頁或30萬頁。 

雖然在超大容量狀況下,這個分頁的實現過程是很快的,但在分前幾頁時,這個1-3秒的速度比起第一種甚至沒有通過優化的分頁方法速度還要慢,借用戶的話說就是「尚未ACCESS數據庫速度快」,這個認識足以致使用戶放棄使用您開發的系統。

  筆者就此分析了一下,原來產生這種現象的癥結是如此的簡單,但又如此的重要:排序的字段不是彙集索引!    

     本篇文章的題目是:「查詢優化及分頁算法方案」。筆者只因此把「查詢優化」和「分頁算法」這兩個聯繫不是很大的論題放在一塊兒,就是由於兩者都須要一個很是重要的東西――彙集索引。  在前面的討論中咱們已經提到了,彙集索引有兩個最大的優點:    

     一、以最快的速度縮小查詢範圍。    

     二、以最快的速度進行字段排序。 
第1條多用在查詢優化時,而第2條多用在進行分頁時的數據排序。 
  而彙集索引在每一個表內又只能創建一個,這使得彙集索引顯得更加的重要。彙集索引的挑選能夠說是實現「查詢優化」和「高效分頁」的最關鍵因素。    

      但要既使彙集索引列既符合查詢列的須要,又符合排序列的須要,這一般是一個矛盾。    

      筆者前面「索引」的討論中,將fariqi,即用戶發文日期做爲了彙集索引的起始列,日期的精確度爲「日」。這種做法的優勢,前面已經提到了,在進行劃時間段的快速查詢中,比用ID主鍵列有很大的優點。 
     但在分頁時,因爲這個彙集索引列存在着重複記錄,因此沒法使用max或min來最爲分頁的參照物,進而沒法實現更爲高效的排序。而若是將ID主鍵列做爲彙集索引,那麼彙集索引除了用以排序以外,沒有任何用處,其實是浪費了彙集索引這個寶貴的資源。

  爲解決這個矛盾,筆者後來又添加了一個日期列,其默認值爲getdate()。用戶在寫入記錄時,這個列自動寫入當時的時間,時間精確到毫秒。即便這樣,爲了不可能性很小的重合,還要在此列上建立UNIQUE約束。將此日期列做爲彙集索引列。 
  有了這個時間型彙集索引列以後,用戶就既能夠用這個列查找用戶在插入數據時的某個時間段的查詢,又能夠做爲惟一列來實現max或min,成爲分頁算法的參照物。    

通過這樣的優化,筆者發現,不管是大數據量的狀況下仍是小數據量的狀況下,分頁速度通常都是幾十毫秒,甚至0毫秒。而用日期段縮小範圍的查詢速度比原來也沒有任何遲鈍。  彙集索引是如此的重要和珍貴,因此筆者總結了一下,必定要將彙集索引創建在:    

一、您最頻繁使用的、用以縮小查詢範圍的字段上;    

二、您最頻繁使用的、須要排序的字段上。

相關文章
相關標籤/搜索