SQL Server索引設計 <第五篇>

來源:互聯網
上載者:User

標籤:ble   最佳化器   sqlserver   電話   影響   類型   應用   辦公   大資料   

  SQL Server索引的設計主要考慮因素如下:

  檢查WHERE條件和串連條件列;

  使用窄索引;

  檢查列的選擇性;

  檢查列的資料類型;

  考慮列順序;

  考慮索引類型(叢集索引OR非叢集索引);

一、檢查WHERE條件列和連結條件列

  當一個查詢提交到SQL Server時,查詢最佳化工具嘗試為查詢中引用的所有表尋找最佳的資料訪問機制。下面列出查詢最佳化工具針對WHERE和串連的工作方式:

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

  為了理解WHERE子句在查詢中的重要性,來考慮一個樣本。

  SELECT * FROM Person WHERE Id = 100;

  假設上面的表Id列為叢集索引。上面的語句有了WHERE子句,查詢最佳化工具將檢查WHERE子句的列Id,確定Id列上有叢集索引,從叢集索引上的統計評估WHERE子句的高選擇性,並且決定使用這個索引。

  查詢最佳化工具的表現說明,WHERE子句列協助最佳化器選擇一個對查詢最優的索引操作。這也適用於兩個表之間的串連條件中使用的列。最佳化器尋找到WHERE子句或串連條件列上的索引,如果可用,考慮使用該索引來從表中檢索行。查詢最佳化工具在執行一個查詢時,考慮WHERE子句或串連條件列上的索引。因此WHERE子句或串連條件中頻繁使用的列上有索引將協助最佳化器避免基本表的掃描。

  但是,當一個表中的資料總量非常小以至於可以放入一個資料頁,那麼表掃描可能比索引尋找更快,如果有一個好的索引,但是仍然進行掃描,可以考慮這個問題。

二、使用窄索引

  可以在表中的一個列組合上建立索引,但是為了最好的效能,盡量在索引中使用較少的列。還應該避免在索引中使用寬資料類型的列。

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

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

  1. 減少I/O數量(讀取更少的8KB頁面);
  2. 使資料庫緩衝更有效,因為SQL Server可以緩衝更少的索引頁面,從而減少記憶體中的索引頁面所需的邏輯讀操作;
  3. 減少資料庫儲存空間;

   下面以後一個樣本來說明窄索引的好處:

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

   

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

  

  我們看到。包含多了兩個列之後,邏輯讀取比一個列多?為什麼呢?因為包含多了兩個列,索引需要佔用更大的空間,一個資料頁放的索引行少了,就需要讀取更多的資料頁。

三、索引列的選擇性

  索引,特別是非叢集索引,主要在索引中有相當進階別的選擇性的情況下是有益的。所謂選擇性,指的是列中唯一值的百分比。列中的唯一值百分比越高,選擇性就越高,從而索引的溢出就越大。如果一個表中有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的選擇來看,基本上可以得出一個結論,邏輯讀比預讀更加佔用時間。

四、檢查索引的資料類型

  索引列的資料類型也是很重要的。例如,在一個整數索引值上的索引查詢是非常快的,這是因為int資料類型的尺寸很小,而且算數操縱很容易。也可以使用int資料的其他變種(bigint,smallint,tinyint)作為索引列,而字串資料型別(char、varchar、nchar、ncarchar、)需要字串匹配操作,這通常比整數匹配操作的開銷更大。

   假設希望在一列上建立索引但卻有兩個候選列,一個是int資料類型,一個是char(4)資料類型。這兩種資料類型在SQL Server 2008中大小都是4位元組,但是仍然應該首選int資料類型作為索引。因為char(4)資料類型中的值1實際上儲存為1後面跟著3個空格,4個位元組組合是0x35、0x20、0x20、0x20。CPU不理解如何在這個資料上執行算數運算。因此在算數操作之前要將其轉換為一個整數,而在int資料類型中,值1被儲存為0x00000001。CPU可以簡單地在這個資料上執行算數運算。

五、索引列順序

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

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

  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上排序。

  這就好比使用電話本。所有項都是按先姓後名的方式進行索引-如果值知道要通電話的人的名是“備”,那麼這種排列順序不能帶來什麼好處。另一方面,如果只知道他的姓是“劉”,那麼索引將可以用來縮小尋找範圍。

六、考慮索引類型

  考慮索引的類型 SQL Server中有兩種主要的索引類型:叢集索引和非叢集索引。這兩種類型都為B-樹結構。兩者之間的主要區別是叢集索引中的葉子頁是表的資料。因此表中的資料和叢集索引的順序相同,這意味著,叢集索引就是該表。在決定使用索引類型時,兩種索引類型的葉子層級上的差別變得非常重要。

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

  SQLServer在預設情況下,主鍵和叢集索引是一起建立的。如果不想將主鍵聲明為叢集索引,那麼在建立表時,只需添加NONCLUSTERED關鍵字。

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

  一旦建立了索引,改變它的唯一方法是刪除和重建它,所以需要一開始就做對。

  如果改變了叢集索引所在的列,那麼SQL Server將需要對整個表完全重新排序(因為對於叢集索引,表的排列順序和索引順序是相同的)。

  對於資料比較多的表,改變叢集索引,需要重新排序的資料非常多,要從以下幾個方面進行考慮。

  它將需要花費多長時間。
  是否有足夠的空間?為了在叢集索引上執行重新排序,額外需要的平均空間量將為表已經佔用空間量的1.2倍。確保有足夠的空間來操作。
  應當使用SORT_IN_TEMPDB選項嗎?如果tempdb位於與主要資料庫不同的物理陣列上,並且它有足夠的空間,那麼答案是肯定的。

  1、正面觀點

  如果列常作為範圍查詢的對象,那麼叢集索引對這類查詢是很有用的。這類查詢通常使用between語句或<or>符號。使用GROUP BY以及利用MAX、MIN和COUNT彙總函式的查詢也是使用範圍和偏好叢集索引的查詢的重要樣本。叢集索引適合用於此處,是因為搜尋可以直接到達物理資料中的特定點,可一直讀資料,直到範圍的末端,然後停止。這種方法非常有效。當想要資料基於聚集鍵排序(ORDER BY),聚集也是極好的方法。

  2、反面觀點

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

  (1)、當有更好的位置來使用它時。不要因為列看上去適合做叢集索引就將它用作叢集索引(主鍵是最常見的罪魁禍首)-要確定沒有更合適的其他列。

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

  例如,一個交易系統,用

  ARXXXX

  GLXXXX

  APXXXX

  作為主鍵,並使用預設的叢集索引,那麼在插入資料的時候,經常會發生頁面分割。因為資料會按照叢集索引進行排序,那麼不停的錄入資料,就可能會經常性地發生頁面分割,引起短暫停頓。

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

  選擇在插入時是連續的聚集鍵。可以以此建立一個識別欄位,或者也可以使用另一個列,該列對於任何輸入交易來說,在邏輯上都是連續的。

  選擇不在這個表上使用叢集索引。對於類似的這裡的情形來說,這通常是最好的選擇,因為在對上非叢集索引中的插入一般比在聚集鍵上的插入更快。  

  何時應該使用叢集索引與非叢集索引

動作描述      使用叢集索引    使用非叢集索引
列經常被分組排序    應          應
返回某範圍內的資料  應          不應
一個或極少不同值   不應        不應
小數目的不同值    應          不應
大數目的不同值     不應        應
頻繁更新的列    不應        應
外鍵列        應          應
主鍵列        應          應
頻繁修改索引列     不應        應

  事實上,我們可以通過前面叢集索引和非叢集索引的定義的例子來理解上表。如:返回某範圍內的資料一項。比如你的某個表有一個時間列,恰好您把彙總索引建立在了該列,這時你查詢2010年1月1日到2013年1月1日之間的全部資料時,這個速度就將是很快的,因為你的這本欄位本文是按日期進行排序的,叢集索引只需要找到要檢索的所有資料中的開頭和結尾資料即可;而不像非叢集索引,必須先查到目錄中查到每一項資料對應的頁碼,然後再根據頁碼查到具體內容。

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

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

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列上,就像以上的第1、2種情況,在網頁上的表現就是逾時,根本就無法顯示。這也是我摒棄ID列作為叢集索引的一個最重要的因素。 

得出以上速度的方法是:在各個select語句前加:declare @d datetime 
set @d=getdate() 

並在select語句後加: 
select [語句執行花費時間(毫秒)]=datediff(ms,@d,getdate())

2、只要建立索引就能顯著提高查詢速度

  事實上,我們可以發現上面的例子中,第2、3條語句完全相同,且建立索引的欄位也相同;不同的僅是前者在fariqi欄位上建立的是非彙總索引,後者在此欄位上建立的是彙總索引,但查詢速度卻有著天壤之別。所以,並非是在任何欄位上簡單地建立索引就能提高查詢速度。從建表的語句中,我們可以看到這個有著1000萬資料的表中fariqi欄位有5003個不同記錄。在此欄位上建立彙總索引是再合適不過了。在現實中,我們每天都會發幾個檔案,這幾個檔案的發文日期就相同,這完全符合建立叢集索引要求的:“既不能絕大多數都相同,又不能只有極少數相同”的規則。由此看來,我們建立“適當”的彙總索引對於我們提高查詢速度是非常重要的。 事實上,我們可以發現上面的例子中,第2、3條語句完全相同,且建立索引的欄位也相同;不同的僅是前者在fariqi欄位上建立的是非彙總索引,後者在此欄位上建立的是彙總索引,但查詢速度卻有著天壤之別。所以,並非是在任何欄位上簡單地建立索引就能提高查詢速度。從建表的語句中,我們可以看到這個有著1000萬資料的表中fariqi欄位有5003個不同記錄。在此欄位上建立彙總索引是再合適不過了。在現實中,我們每天都會發幾個檔案,這幾個檔案的發文日期就相同,這完全符合建立叢集索引要求的:“既不能絕大多數都相同,又不能只有極少數相同”的規則。由此看來,我們建立“適當”的彙總索引對於我們提高查詢速度是非常重要的。

3、把所有需要提高查詢速度的欄位都加進叢集索引,以提高查詢速度

  上面已經談到:在進行資料查詢時都離不開欄位的是“日期”還有使用者本身的“使用者名稱”。既然這兩個欄位都是如此的重要,我們可以把他們合并起來,建立一個複合索引(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毫秒

  從以上實驗中,我們可以看到如果僅用叢集索引的起始列作為查詢條件和同時用到複合叢集索引的全部列的查詢速度是幾乎一樣的,甚至比用上全部的複合索引列還要略快(在查詢結果集數目一樣的情況下);而如果僅用複合叢集索引的非起始列作為查詢條件的話,這個索引是不起任何作用的。當然,語句1、2的查詢速度一樣是因為查詢的條目數一樣,如果複合索引的所有列都用上,而且查詢結果少的話,這樣就會形成“索引覆蓋”,因而效能可以達到最優。同時,請記住:無論您是否經常使用彙總索引的其他列,但其前置列一定要是使用最頻繁的列。 


其他書上沒有的索引使用經驗總結 
1、用彙總索引比用不是彙總索引的主鍵速度快 
下面是執行個體語句:(都是提取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。 

2、用彙總索引列比用一般的主鍵作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萬以上,則二者的速度差別不明顯。

3、使用彙總索引列內的時間段,搜尋時間會按資料占整個資料表的百分比成比例減少,而無論彙總索引使用了多少個

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毫秒 
5、其他注意事項 
  “水可載舟,亦可覆舟”,索引也一樣。索引有助於提高檢索效能,但過多或不當的索引也會導致系統低效。因為使用者在表中每加進一個索引,資料庫就要做更多的工作。過多的索引甚至會導致索引片段。 
  所以說,我們要建立一個“適當”的索引體系,特別是對彙總索引的建立,更應精益求精,以使您的資料庫能得到高效能的發揮。 
  當然,在實踐中,作為一個盡職的資料庫管理員,您還要多測試一些方案,找出哪種方案效率最高、最為有效。

六、叢集索引的重要性和如何選擇叢集索引

  在上一節的標題中,筆者寫的是:實現小資料量和海量資料的通用分頁顯示預存程序。這是因為在將本預存程序應用於“辦公自動化”系統的實踐中時,筆者發現這第三種預存程序在小資料量的情況下,有如下現象: 

1、分頁速度一般維持在1秒和3秒之間。 

2、在查詢最後一頁時,速度一般為5秒至8秒,哪怕分頁總數只有3頁或30萬頁。 
雖然在超大容量情況下,這個分頁的實現過程是很快的,但在分前幾頁時,這個1-3秒的速度比起第一種甚至沒有經過最佳化的分頁方法速度還要慢,借使用者的話說就是“還沒有ACCESS資料庫速度快”,這個認識足以導致使用者放棄使用您開發的系統。

  筆者就此分析了一下,原來產生這種現象的癥結是如此的簡單,但又如此的重要:排序的欄位不是叢集索引! 
  本篇文章的題目是:“查詢最佳化及分頁演算法方案”。筆者只所以把“查詢最佳化”和“分頁演算法”這兩個聯絡不是很大的論題放在一起,就是因為二者都需要一個非常重要的東西――叢集索引。 
在前面的討論中我們已經提到了,叢集索引有兩個最大的優勢: 
  1、以最快的速度縮小查詢範圍。 
  2、以最快的速度進列欄位排序。 

第1條多用在查詢最佳化時,而第2條多用在進行分頁時的資料排序。 

  而叢集索引在每個表內又只能建立一個,這使得叢集索引顯得更加的重要。叢集索引的挑選可以說是實現“查詢最佳化”和“高效分頁”的最關鍵因素。 
  但要既使叢集索引列既符合查詢列的需要,又符合排序列的需要,這通常是一個矛盾。 
  筆者前面“索引”的討論中,將fariqi,即使用者發文日期作為了叢集索引的起始列,日期的精確度為“日”。這種作法的優點,前面已經提到了,在進行劃時間段的快速查詢中,比用ID主鍵列有很大的優勢。 

但在分頁時,由於這個叢集索引列存在著重複記錄,所以無法使用max或min來最為分頁的參照物,進而無法實現更為高效的排序。而如果將ID主鍵列作為叢集索引,那麼叢集索引除了用以排序之外,沒有任何用處,實際上是浪費了叢集索引這個寶貴的資源。

  為解決這個矛盾,筆者後來又添加了一個日期列,其預設值為getdate()。使用者在寫入記錄時,這個列自動寫入當時的時間,時間精確到毫秒。即使這樣,為了避免可能性很小的重合,還要在此列上建立UNIQUE約束。將此日期列作為叢集索引列。 

  有了這個時間型叢集索引列之後,使用者就既可以用這個列尋找使用者在插入資料時的某個時間段的查詢,又可以作為唯一列來實現max或min,成為分頁演算法的參照物。 
  經過這樣的最佳化,筆者發現,無論是大資料量的情況下還是小資料量的情況下,分頁速度一般都是幾十毫秒,甚至0毫秒。而用日期段縮小範圍的查詢速度比原來也沒有任何遲鈍。 
叢集索引是如此的重要和珍貴,所以筆者總結了一下,一定要將叢集索引建立在: 
  1、您最頻繁使用的、用以縮小查詢範圍的欄位上; 
  2、您最頻繁使用的、需要排序的欄位上。

 

SQL Server索引設計 <第五篇>

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.