索引技術(轉)

 索引技術
                                     

一、數據表的基本結構

爲認識索引工作原理,首先有必要對數據表的基本結構作一次全面的複習。

SQLS 當一個新表被創建之時,系統將在磁盤中分配一段以8K爲單位的連續空間,當字段的值從內存寫入磁盤時,就在這一既定空間隨機保存,當一個8K用完的時候, SQLS指針會自動分配一個8K的空間。這裏,每個8K空間被稱爲一個數據頁(Page),又名頁面或數據頁面,並分配從0-7的頁號,每個文件的第0頁記錄引導信息,叫文件頭(File header);每8個數據頁(64K)的組合形成擴展區(Extent),稱爲擴展。全部數據頁的組合形成堆(Heap)。

SQLS 規定行不能跨越數據頁,所以,每行記錄的最大數據量只能爲8K。這就是char和varchar這兩種字符串類型容量要限制在8K以內的原因,存儲超過 8K的數據應使用text類型,實際上,text類型的字段值不能直接錄入和保存,它只是存儲一個指針,指向由若干8K的文本數據頁所組成的擴展區,真正的數據正是放在這些數據頁中。

頁面有空間頁面和數據頁面之分。

當一個擴展區的8個數據頁中既包含了空間頁面又包括了數據或索引頁面時,稱爲混合擴展(Mixed Extent),每張表都以混合擴展開始;反之,稱爲一致擴展(Uniform Extent),專門保存數據及索引信息。

表被創建之時,SQLS在混合擴展中爲其分配至少一個數據頁面,隨着數據量的增長,SQLS可即時在混合擴展中分配出7個頁面,當數據超過8個頁面時,則從一致擴展中分配數據頁面。

  空間頁面專門負責數據空間的分配和管理,包括:PFS頁面(Page free space):記錄一個頁面是否已分配、位於混合擴展還是一致擴展以及頁面上還有多少可用空間等信息;GAM頁面(Global allocation map)和SGAM頁面(Secodary global allocation map):用來記錄空閒的擴展或含有空閒頁面的混合擴展的位置。SQLS綜合利用這三種類型的頁面文件在必要時爲數據表創建新空間;

數據頁或索引頁則專門保存數據及索引信息,SQLS使用4種類型的數據頁面來管理表或索引:它們是IAM頁、數據頁、文本/圖像頁和索引頁。

在WINDOWS 中,我們對文件執行的每一步操作,在磁盤上的物理位置只有系統(system)才知道;SQL SERVER沿襲了這種工作方式,在插入數據的過程中,不但每個字段值在數據頁面中的保存位置是隨機的,而且每個數據頁面在“堆”中的排列位置也只有系統(system)才知道。

這是爲什麼呢?衆所周知,OS 之所以能管理DISK,是因爲在系統啓動時首先加載了文件分配表:FAT(File Allocation Table),正是由它管理文件系統並記錄對文件的一切操作,系統才得以正常運行;同理,作爲管理系統級的SQL SERVER,也有這樣一張類似FAT的表存在,它就是索引分佈映像頁:IAM(Index Allocation Map)。

IAM的存在,使SQLS對數據表的物理管理有了可能。

IAM 頁從混合擴展中分配,記錄了8個初始頁面的位置和該擴展區的位置,每個IAM頁面能管理512,000個數據頁面,如果數據量太大,SQLS也可以增加更多的IAM頁,可以位於文件的任何位置。第一個IAM頁被稱爲FirstIAM,其中記錄了以後的IAM頁的位置。

數據頁和文本/圖像頁互反,前者保存非文本/圖像類型的數據,因爲它們都不超過8K的容量,後者則只保存超過8K容量的文本或圖像類型數據。而索引頁顧名思義,保存的是與索引結構相關的數據信息。瞭解頁面的問題有助我們下一步準確理解SQLS維護索引的方式,如頁拆分、填充因子等。

 

二、索引的基本概念

索引是一種特殊類型的數據庫對象,它與表有着密切的聯繫。

索引是爲檢索而存在的。如一些書籍的末尾就專門附有索引,指明瞭某個關鍵字在正文中的出現的頁碼位置,方便我們查找,但大多數的書籍只有目錄,目錄不是索引,只是書中內容的排序,並不提供真正的檢索功能。可見建立索引要單獨佔用空間;索引也並不是必須要建立的,它們只是爲更好、更快的檢索和定位關鍵字而存在。

再進一步說,我們要在圖書館中查閱圖書,該怎麼辦呢?圖書館的前臺有很多叫做索引卡片櫃的小櫃子,裏面分了若干的類別供我們檢索圖書,比如你可以用書名的筆畫順序或者拼音順序作爲查找的依據,你還可以從作者名的筆畫順序或拼音順序去查詢想要的圖書,反正有許多檢索方式,但有一點很明白,書庫中的書並沒有按照這些卡片櫃中的順序排列——雖然理論上可以這樣做,事實上,所有圖書的脊背上都人工的粘貼了一個特定的編號①,它們是以這個順序在排列。索引卡片中並沒有指明這本書擺放在書庫中的第幾個書架的第幾本,僅僅指明瞭這個特定的編號。管理員則根據這一編號將請求的圖書返回到讀者手中。這是很形象的例子,以下的講解將會反覆用到它。

SQLS 在安裝完成之後,安裝程序會自動創建master、model、tempdb等幾個特殊的系統數據庫,其中master是SQLS的主數據庫,用於保存和管理其它系統數據庫、用戶數據庫以及SQLS的系統信息,它在SQLS中的地位與WINDOWS下的註冊表相當。

master中有一個名爲sysindexes的系統表,專門管理索引。SQLS查詢數據表的操作都必須用到它,毫無疑義,它是本文主角之一。

查看一張表的索引屬性,可以在查詢分析器中使用以下命令:select * from sysindexes where id=object_id(‘tablename’) ;而要查看錶的索引所佔空間的大小,可以使用系統存儲過程命令:sp_spaceused tablename,其中參數tablename爲被索引的表名。

 

三、平衡樹

如果你通過書後的索引知道了一個關鍵字所在的頁碼,你有可能通過隨機的翻尋,最終到達正確的頁碼。但更科學更快捷的方法是:首先把書翻到大概二分之一的位置,如果要找的頁碼比該頁的頁碼小,就把書向前翻到四分之一處,否則,就把書向後翻到四分之三的地方,依此類推,把書頁續分成更小的部分,直至正確的頁碼。這叫“兩分法”,微軟在官方教程MOC裏另有一種說法:叫B樹(B-Tree,Balance Tree),即平衡樹。

一個表索引由若干頁面組成,這些頁面構成了一個樹形結構。B 樹由“根”(root)開始,稱爲根級節點,它通過指向另外兩個頁,把一個表的記錄從邏輯上分成兩個部分:“枝”—--非葉級節點(Non-Leaf Level);而非葉級節點又分別指向更小的部分:“葉”——葉級節點(Leaf Level)。根節點、非葉級節點和葉級節點都位於索引頁中,統稱爲索引節點,屬於索引頁的範籌。這些“枝”、“葉”最終指向了具體的數據頁(Page)。在根級節點和葉級節點之間的葉又叫數據中間頁。

“根”(root)對應了sysindexes表的Root字段,其中記載了非葉級節點的物理位置(即指針);非葉級節點位於根節點和葉節點之間,記載了指向葉級節點的指針;而葉級節點則最終指向數據頁。這就是“平衡樹”。

 

四、聚集索引和非聚集索引

從形式上而言,索引分爲聚集索引(Clustered Indexes)和非聚集索引(NonClustered Indexes)。

聚集索引相當於書籍脊背上那個特定的編號。如果對一張表建立了聚集索引,其索引頁中就包含着建立索引的列的值(下稱索引鍵值),那麼表中的記錄將按照該索引鍵值進行排序。比如,我們如果在“姓名”這一字段上建立了聚集索引,則表中的記錄將按照姓名進行排列;如果建立了聚集索引的列是數值類型的,那麼記錄將按照該鍵值的數值大小來進行排列。

非聚集索引用於指定數據的邏輯順序,也就是說,表中的數據並沒有按照索引鍵值指定的順序排列,而仍然按照插入記錄時的順序存放。其索引頁中包含着索引鍵值和它所指向該行記錄在數據頁中的物理位置,叫做行定位符(RID:Row ID)。好似書後面的的索引表,索引表中的順序與實際的頁碼順序也是不一致的。而且一本書也許有多個索引。比如主題索引和作者索引。

SQL Server在默認的情況下建立的索引是非聚集索引,由於非聚集索引不對錶中的數據進行重組,而只是存儲索引鍵值並用一個指針指向數據所在的頁面。一個表如果沒有聚集索引時,理論上可以建立249個非聚集索引。每個非聚集索引提供訪問數據的不同排序順序。

 

五、數據是怎樣被訪問的

若能真正理解了以上索引的基礎知識,那麼再回頭來看索引的工作原理就簡單和輕鬆多了。

(一)SQLS怎樣訪問沒有建立任何索引數據表:

Heap 譯成漢語叫做“堆”,其本義暗含雜亂無章、無序的意思,前面提到數據值被寫進數據頁時,由於每一行記錄之間並沒地有特定的排列順序,所以行與行的順序就是隨機無序的,當然表中的數據頁也就是無序的了,而表中所有數據頁就形成了“堆”,可以說,一張沒有索引的數據表,就像一個只有書櫃而沒有索引卡片櫃的圖書館,書庫裏面塞滿了一堆亂七八糟的圖書。當讀者對管理員提交查詢請求後,管理員就一頭鑽進書庫,對照查找內容從頭開始一架一櫃的逐本查找,運氣好的話,在第一個書架的第一本書就找到了,運氣不好的話,要到最後一個書架的最後一本書才找到。

SQLS 在接到查詢請求的時候,首先會分析sysindexes表中一個叫做索引標誌符(INDID: Index ID)的字段的值,如果該值爲0,表示這是一張數據表而不是索引表,SQLS就會使用sysindexes表的另一個字段——也就是在前面提到過的 FirstIAM值中找到該表的IAM頁鏈——也就是所有數據頁集合。

這就是對一個沒有建立索引的數據表進行數據查找的方式,是不是很沒效率?對於沒有索引的表,對於一“堆”這樣的記錄,SQLS也只能這樣做,而且更沒勁的是,即使在第一行就找到了被查詢的記錄,SQLS仍然要從頭到尾的將表掃描一次。這種查詢稱爲“遍歷”,又叫“表掃描”。

可見沒有建立索引的數據表照樣可以運行,不過這種方法對於小規模的表來說沒有什麼太大的問題,但要查詢海量的數據效率就太低了。

(二)SQLS怎樣訪問建立了非聚集索引的數據表:

如前所述,非聚集索引可以建多個,具有B樹結構,其葉級節點不包含數據頁,只包含索引行。假定一個表中只有非聚集索引,則每個索引行包含了非聚集索引鍵值以及行定位符(ROW ID,RID),他們指向具有該鍵值的數據行。每一個RID由文件ID、頁編號和在頁中行的編號組成。

當INDID 的值在2-250之間時,意味着表中存在非聚集索引頁。此時,SQLS調用ROOT字段的值指向非聚集索引B樹的ROOT,在其中查找與被查詢最相近的值,根據這個值找到在非葉級節點中的頁號,然後順藤摸瓜,在葉級節點相應的頁面中找到該值的RID,最後根據這個RID在Heap中定位所在的頁和行並返回到查詢端。

例如:假定在Lastname上建立了非聚集索引,則執行Select * From Member Where Lastname=’Ota’時,查詢過程是:①SQLS 查詢INDID值爲2;②立即從根出發,在非葉級節點中定位最接近Ota的值“Martin”,並查到其位於葉級頁面的第61頁;③僅在葉級頁面的第61 頁的Martin下搜尋Ota的RID,其RID顯示爲N∶706∶4,表示Lastname字段中名爲Ota的記錄位於堆的第707頁的第4行,N表示文件的ID值,與數據無關;④根據上述信息,SQLS立馬在堆的第 707頁第4行將該記錄“揪”出來並顯示於前臺(客戶端)。視表的數據量大小,整個查詢過程費時從百分之幾毫秒到數毫秒不等。

在談到索引基本概念的時候,我們就提到了這種方式:

圖書館的前臺有很多索引卡片櫃,裏面分了若干的類別,諸如按照書名筆畫或拼音順序、作者筆畫或拼音順序等等,但不同之處有二:① 索引卡片上記錄了每本書擺放的具體位置——位於某櫃某架的第幾本——而不是“特殊編號”;② 書脊上並沒有那個“特殊編號”。管理員在索引櫃中查到所需圖書的具體位置(RID)後,根據RID直接在書庫中的具體位置將書提出來。

顯然,這種查詢方式效率很高,但資源佔用極大,因爲書庫中書的位置隨時在發生變化,必然要求管理員花費額外的精力和時間隨時做好索引更新。

(三)SQLS怎樣訪問建立了聚集索引的數據表:

在聚集索引中,數據所在的數據頁是葉級,索引數據所在的索引頁是非葉級。

查詢原理和上述對非聚集索引的查詢相似,但由於記錄是按照聚集索引中索引鍵值進行排序,換句話說,聚集索引的索引鍵值也就是具體的數據頁。

這就好比書庫中的書就是按照書名的拼音在排序,而且也只按照這一種排序方式建立相應的索引卡片,於是查詢起來要比上述只建立非聚集索引的方式要簡單得多。仍以上面的查詢爲例:

假定在Lastname字段上建立了聚集索引,則執行Select * From Member Where Lastname=’Ota’時,查詢過程是:①SQLS查詢INDID值爲1,這是在系統中只建立了聚集索引的標誌;②立即從根出發,在非葉級節點中定位最接近Ota的值“Martin”,並查到其位於葉級頁面的第120頁;③在位於葉級頁面第120頁的Martin下搜尋到Ota條目,而這一條目已是數據記錄本身;④將該記錄返回客戶端。

這一次的效率比第二種方法更高,以致於看起來更美,然而它最大的優點也恰好是它最大的缺點——由於同一張表中同時只能按照一種順序排列,所以在任何一種數據表中的聚集索引只能建立一個;並且建立聚集索引需要至少相當於源表120%的附加空間,以存放源表的副本和索引中間頁!

難道魚和熊掌就不能兼顧了嗎?辦法是有的。

(四)SQLS怎樣訪問既有聚集索引、又有非聚集索引的數據表:

如果我們在建立非聚集索引之前先建立了聚集索引的話,那麼非聚集索引就可以使用聚集索引的關鍵字進行檢索,就像在圖書館中,前臺卡片櫃中的可以有不同類別的圖書索引卡,然而每張卡片上都載明瞭那個特殊編號——並不是書籍存放的具體位置。這樣在最大程度上既照顧了數據檢索的快捷性,又使索引的日常維護變得更加可行,這是最爲科學的檢索方法。

也就是說,在只建立了非聚集索引的情況下,每個葉級節點指明瞭記錄的行定位符(RID);而在既有聚集索引又有非聚集索引的情況下,每個葉級節點所指向的是該聚集索引的索引鍵值,即數據記錄本身。

假設聚集索引建立在Lastname上,而非聚集索引建立在Firstname上,當執行Select * From Member Where Firstname=’Mike’時,查詢過程是:①SQLS查詢INDID值爲2;②立即從根出發,在Firstname的非聚集索引的非葉級節點中定位最接近Mike的值“Jose”條目;③從Jose條目下的葉級頁面中查到Mike邏輯位置——不是RID而是聚集索引的指針;④根據這一指針所指示位置,直接進入位於Lastname的聚集索引中的葉級頁面中到達Mike數據記錄本身;⑤將該記錄返回客戶端。

這就完全和我們在“索引的基本概念”中講到的現實場景完全一樣了,當數據發生更新的時候,SQLS 只負責對聚集索引的健值駕以維護,而不必考慮非聚集索引,只要我們在ID類的字段上建立聚集索引,而在其它經常需要查詢的字段上建立非聚集索引,通過這種科學的、有針對性的在一張表上分別建立聚集索引和非聚集索引的方法,我們既享受了索引帶來的靈活與快捷,又相對規避了維護索引所導致的大量的額外資源消耗。

 

六、索引的優點和不足

索引有一些先天不足:1:建立索引,系統要佔用大約爲表的1.2倍的硬盤和內存空間來保存索引。2:更新數據的時候,系統必須要有額外的時間來同時對索引進行更新,以維持數據和索引的一致性——這就如同圖書館要有專門的位置來擺放索引櫃,並且每當庫存圖書發生變化時都需要有人將索引卡片重整以保持索引與庫存的一致。

當然建立索引的優點也是顯而易見的:在海量數據的情況下,如果合理的建立了索引,則會大大加強SQLS執行查詢、對結果進行排序、分組的操作效率。

   實踐表明,不恰當的索引不但於事無補,反而會降低系統性能。因爲大量的索引在進行插入、修改和刪除操作時比沒有索引花費更多的系統時間。比如在如下字段建立索引應該是不恰當的:1、很少或從不引用的字段;2、邏輯型的字段,如男或女(是或否)等。

綜上所述,提高查詢效率是以消耗一定的系統資源爲代價的,索引不能盲目的建立,必須要有統籌的規劃,一定要在“加快查詢速度”與“降低修改速度”之間做好平衡,有得必有失,此消則彼長。這是考驗一個DBA是否優秀的很重要的指標。                                        

上期,我們就索引的基本概念和數據查詢原理作了詳細闡述,知道了建立索引時一定要在“加快查詢速度”與“降低修改速度”之間做好平衡,有得必有失,此消則彼長。那麼,SQLS維護索引時究竟怎樣消耗資源?應該從哪些方面對索引進行管理與優化?以下從六個方面來回答這些問題:

一.頁分裂

微軟MOC教導我們:當一個數據頁達到了8K容量,如果此時發生插入或更新數據的操作,將導致頁的分裂(又名頁拆分):

1.有聚集索引的情況下:聚集索引將被插入和更新的行指向特定的頁,該頁由聚集索引關鍵字決定;

2.只有堆的情況下:只要有空間就可以插入新的行,但是如果我們對行數據的更新需要更多的空間,以致大於當前頁的可用空間,行就被移到新的頁中,並且在原位置留下一個轉發指針,指向被移動的新行,如果具有轉發指針的行又被移動了,那麼原來的指針將重新指向新的位置;

3.如果堆中有非聚集索引,那麼儘管插入和更新操作在堆中不會發生頁分裂,但是在非聚集索引上仍然產生頁分裂。

無論有無索引,大約一半的數據將保留在老頁面,而另一半將放入新頁面,並且新頁面可能被分配到任何可用的頁。所以,頻繁頁分裂,後果很嚴重,將使物理表產生大量數據碎片,導致直接造成I/O效率的急劇下降,最後,不得不停止SQLS的運行並重建索引。

二.填充因子

然而在“混沌之初”,就可以在一定程度上避免不愉快出現,在創建索引時,可以爲這個索引指定一個填充因子,以便在索引的每個葉級頁面上保留一定百分比的空間,將來數據可以進行擴充和減少頁分裂。填充因子是從0到100的百分比數值,設爲100時表示將數據頁填滿,只有當不會對數據進行更改時(例如只讀表中)才用此設置。值越小則數據頁上的空閒空間越大,這樣可以減少在索引增長過程中進行頁分裂的需要,但這一操作需要佔用更多的硬盤空間。

填充因子只在創建索引時執行,索引創建以後,當表中進行數據的添加、刪除或更新時,是不會保持填充因子的,如果想在數據頁上保持額外的空間,則有悖於使用填充因子的本意,因爲隨着數據的輸入,SQLS必須在每個頁上進行頁拆分,以保持填充因子指定的空閒空間。因此,只有在表中的數據進行了較大的變動,纔可以填充數據頁的空閒空間。這時,可以從容的重建索引,重新指定填充因子,重新分佈數據。

反之,填充因子指定不當,就會降低數據庫的讀取性能,其降低量與填充因子設置值成反比。例如,當填充因子的值爲50時,數據庫的讀取性能會降低兩倍。所以,只有在表中根據現有數據創建新索引,並且可以預見將來會對這些數據進行哪些更改時,設置填充因子纔有意義。

三.兩道數學題

假定數據庫設計沒有問題,那麼是否像上篇分析的那樣,當你建立了衆多的索引,在查詢工作中SQLS就只能按照“最高指示”用索引處理每一個提交的查詢呢?答案是否定的。

“數據是怎樣被訪問的”一文中提到的四種索引方案只是一種靜態的、標準的和理論上的分析比較。實際上,SQLS幾乎完全是“自主”的決定是否使用索引或使用哪一個索引

這是怎麼回事呢?

讓我們先來算一道題:如果某表的一條記錄在磁盤上佔用1000字節(1K)的話,我們對其中10字節的一個字段建立索引,那麼該記錄對應的索引大小隻有10 字節(0.01K)。上篇說過,SQLS的最小空間分配單元是“頁(Page)”,一個頁面在磁盤上佔用8K空間,所以一頁只能存儲8條“記錄”,但可以存儲800條“索引”。現在我們要從一個有8000條記錄的表中檢索符合某個條件的記錄(有Where子句),如果沒有索引的話,我們需要遍歷8000條 ×1000字節/8K字節=1000個頁面才能夠找到結果。如果在檢索字段上有上述索引的話,那麼我們可以在8000條×10字節/8K字節=10個頁面中就檢索到滿足條件的索引塊,然後根據索引塊上的指針逐一找到結果數據塊,這樣I/O訪問量肯定要少得多。

然而有時用索引比不用索引還快。

同上,如果要無條件檢索全部記錄(不用Where子句),不用索引的話,需要訪問8000條×1000字節/8K字節=1000個頁面;而使用索引的話,首先檢索索引,訪問8000條×10字節/8K字節=10個頁面得到索引檢索結果,再根據索引檢索結果去對應數據頁面,由於是檢索全部數據,所以需要再訪問 8000條×1000字節/8K字節=1000個頁面將全部數據讀取出來,一共訪問了1010個頁面,這顯然不如不用索引快。

SQLS內部有一套完整的數據索引優化技術,在上述情況下,SQLS會自動使用表掃描的方式檢索數據而不會使用任何索引。那麼SQLS是怎麼知道什麼時候用索引,什麼時候不用索引的呢?因爲SQLS除了維護數據信息外,還維護着數據統計信息。

四.統計信息

打開企業管理器,單擊“Database”節點,右擊Northwind數據庫→單擊“屬性”→選擇“Options”選項卡,觀察“Settings”下的各項複選項,你發現了什麼?

從Settings中我們可以看到,在數據庫中,SQLS將默認的自動創建和更新統計信息,這些統計信息包括數據密度和分佈信息,正是它們幫助SQLS確定最佳的查詢策略:建立查詢計劃和是否使用索引以及使用什麼樣的索引。

在創建索引時,SQLS會創建分佈數據頁來存放有關索引的兩種統計信息:分佈表和密度表。查詢優化器使用這些統計信息估算使用該索引進行查詢的成本(Cost),並在此基礎上判斷該索引對某個特定查詢是否有用。

隨着表中的數據發生變化,SQLS自動定期更新這些統計信息。採樣是在各個數據頁上隨機進行。從磁盤讀取一個數據頁後,該數據頁上的所有行都被用來更新統計信息。統計信息更新的頻率取決於字段或索引中的數據量以及數據更改量。比如,對於有一萬條記錄的表,當1000個索引鍵值發生改變時,該表的統計信息便可能需要更新,因爲1000 個值在該表中佔了10%,這是一個很大的比例。而對於有1千萬條記錄的表來說,1000個索引值發生更改的意義則可以忽略不計,因此統計信息就不會自動更新。

五.索引的人工維護

上面講到,某些不合適的索引將影響到SQLS的性能,隨着應用系統的運行,數據不斷地發生變化,當數據變化達到某一個程度時將會影響到索引的使用。這時需要用戶自己來維護索引。

隨着數據行的插入、刪除和數據頁的分裂,有些索引頁可能只包含幾頁數據,另外應用在執行大量I/O的時候,重建非聚聚集索引可以維護I/O的效率。重建索引實質上是重新組織B樹。需要重建索引的情況有:

1.數據和使用模式大幅度變化;

2.排序的順序發生改變;

3.要進行大量插入操作或已經完成;

4.使用I/O查詢的磁盤讀次數比預料的要多;

5.由於大量數據修改,使得數據頁和索引頁沒有充分使用而導致空間的使用超出估算;

6.dbcc檢查出索引有問題。

六.索引的使用原則

接近尾聲的時候,讓我們再從另一個角度認識索引的兩個重要屬性----惟一性索引和複合性索引。

惟一性索引保證在索引列中的全部數據是惟一的,不會包含冗餘數據。如果表中已經有一個主鍵約束或者惟一性約束,那麼當創建表或者修改表時,SQLS自動創建一個惟一性索引。但出於必須保證惟一性,那麼應該創建主鍵約束或者惟一性鍵約束,而不是創建一個惟一性索引。
複合索引就是一個索引創建在兩個列或者多個列上。在搜索時,當兩個或者多個列作爲一個關鍵值時,最好在這些列上創建複合索引。當創建複合索引時,應該考慮這些規則:最多可以把16個列合併成一個單獨的複合索引,構成複合索引的列的總長度不能超過900字節;在複合索引中,所有的列必須來自同一個表中,不能跨表建立複合列;在複合索引中,列的排列順序是非常重要的,原則上,應該首先定義最惟一的列,例如在(COL1,COL2)上的索引與在(COL2, COL1)上的索引是不相同的,因爲兩個索引的列的順序不同;爲了使查詢優化器使用複合索引,查詢語句中的WHERE子句必須參考複合索引中第一個列。

綜上所述,我們總結了如下索引使用原則:

1.邏輯主鍵使用惟一的成組索引,對系統鍵(作爲存儲過程)採用惟一的非成組索引,對任何外鍵列採用非成組索引。考慮數據庫的空間有多大,表如何進行訪問,還有這些訪問是否主要用作讀寫;

2.不要索引memo/note 字段,不要索引大型字段(有很多字符),這樣作會讓索引佔用太多的存儲空間;

3.不要索引常用的小型表;

4.一般不要爲小型數據表設置過多的索引,如果經常有插入和刪除操作就更不要設置索引,因爲SQLS對插入和刪除操作提供的索引維護可能比掃描表空間消耗的時間更多。

查詢是一個物理過程,表面上是SQLS在東跑西跑,其實真正大部分壓馬路的工作是由磁盤輸入輸出系統(I/O)完成,全表掃描需要從磁盤上讀表的每一個數據頁,如果有索引指向數據值,則I/O讀幾次磁盤就可以了。但是,在隨時發生的增、刪、改操作中,索引的存在會大大增加工作量,因此,合理的索引設計是建立在對各種查詢的分析和預測上的,只有正確地使索引與程序結合起來,才能產生最佳的優化方案。

SQLS是一個很複雜的系統,讓索引以及查詢背後的東西真相大白,可以幫助我們更爲深刻的瞭解我們的系統。一句話,索引就像鹽,少則無味多則鹹。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章