1. 程式人生 > >SQL Server索引語法 <第四篇>

SQL Server索引語法 <第四篇>

相同 alt 不能 之間 cto 事情 col 存儲 過程

  從CREATE開始

  •   通過顯式的CREATE INDEX命令
  •   在創建約束時作為隱含的對象

  隨約束創建的隱含索引

  當向表中添加如下兩種約束之一時,就會創建隱含索引。

  1.   主鍵約束(聚集索引)
  2.   唯一約束(唯一索引)

一、CREATE INDEX語法

  CREATE INDEX語句所做的事情與其聽上去一樣-用於在指定表或視圖上基於聲明的列創建索引:

CREATE [UNIQUE] [CLUSTERED | NONCLUSTERED]
INDEX <index name> ON <table or view name>
(<column name> [ASC|DESC][,...n]) INCLUDE (<column name> [,...n]) [ WITH [PAD_INDEX = {ON | OFF}] [[,] FILLFACTOR = <fillfactor>] [[,] IGNORE_DUR_KEY = {ON | OFF}] [[,] DROP_EXISTING = {ON | OFF}] [[,] STATISTICS_NORECOMPUTE = {ON | OFF}] [[,] SORT_IN_TEMPDB = {ON | OFF}] [[,] ONLINE = {ON | OFF}] [[,] ALLOW_ROW_LOCKS = {ON | OFF}] [[,] ALLOW_PAGE_LOCKS = {ON | OFF}] [[,] MAXDOP =
<maxinum degree of parallelism> ] [ON {<filegroup> | <partition scheme name> | DEFAULT}]

  CREATE INDEX語句必須隨表或者視圖出現,並且需要聲明列所在(ON)的表。下面解釋個選項的作用

  1、ASC/DESC

  這兩個選項允許為索引選擇升序和降序排列順序。默認選項為ASC,它是升序。

  為什麽需要升序和降序兩個選項呢?不是反序查看索引不就行了嗎?但是如果一列按升序排列,但是其他列要求按降序排列,怎麽辦呢?因為索引的列是存儲在一起的,所以對一列反向查看索引也將倒轉其他列的順序。如果顯示地聲明某一列是升序,而另一列是降序,那麽將直接在索引的物理數據中倒轉第二列-突然間就不必改變訪問數據的方式了。

  2、INCLUDE

  這是SQL Server2005及後續版本支持的選項。它的目的是為覆蓋查詢(covered queries)提供更好的支持。

  當包含(INCLUDE)列而不是將列放在ON列表上時,SQL Server僅僅在索引的葉級上添加它們。因為在索引葉級上的每一行對應於一個數據行,所以所做的事情在本質上是將更多的原始數據包含在索引的葉級上。這樣做有一個好處,因為SQL Server在有了它實際需要的內容就停止工作。SQL Server在遍歷索引時沒有繼續訪問實際的數據行就找到所需的所有數據,那麽就不必再到達數據行。通過在索引中包含特定的列,可以在葉級“覆蓋”利用該特定索引的查詢,從而節省了與使用索引指針到達數據頁相關的I/O。實際是,比如你為一個日期列創建索引,但是INCLUDE一個訂單ID列。那麽查找某日期的訂單ID,就不必再到實際數據行了,因為在索引中就有了所需的數據。但是註意不要濫用該選項,當包含列時,將增加索引頁的葉級的大小。這意味著每頁中的行數將更少,因此需要更多的I/O來查看相同數量的行。結果可能是,加快了一個查詢的同時可能減慢了其他的查詢。要考慮對系統各個部分的影響,而不是僅僅考慮某個時候正在使用的特定查詢。

  3、WITH

  WITH非常簡單-它只是告訴SQL Server將要提供一個或者多個跟在後面的選項。

  4、PAD_INDEX

  該選項確定了第一次創建索引時,索引的非葉級頁將有多滿(用百分比表示)。不用在PAD_INDEX中聲明百分比,因為將使用後面的FILLTACTOR選項指定的百分比。設置不帶有FILLFACTOR選項的PAD_INDEX=ON將是沒有意義的。

  5、FILLFACTOR

  當SQL Server第一次創建索引時,默認情況下將盡可能地將頁填滿,僅留兩個記錄的控件,可以將FILLTACTOE設置為在0-100之間的任意值。一旦索引構造完成,這個數字將表示頁相對滿的程度的百分比。但是在進行頁拆分時,數據將仍然在兩頁之間對半分布-除了定期重建索引外,不能不斷地控制填充百分比。

  當需要調整頁密度的時候,使用FILLTACTOR需要從以下幾方面考慮:

  •   如果是OLTP系統(經常添加和刪除),那麽需要較低的FILLFACTOR。
  •   如果是OLAP或者其他非常穩定(幾乎沒有添加和刪除)的系統,那麽需要盡可能高的FILLFACTOR。
  •   如果事務比例中等,且有很多基於它的報表類型查詢,那麽可能需要中等水平的FILLFACTOR(不太低,也不太高)。
  •   如果沒有提供值,那麽SQL Server將把頁填充至差兩行滿為止,同時保證每頁至少有一行。(如果行是8000字符寬,那麽每頁只能放一行,所以無法達到差兩行滿)。

  6、IGNORE_DUP_KEY

  IGNORE_DUP_KEY選項幾乎是一種回避系統的方法。簡而言之,它使得唯一約束與其應有的操作方式有些不同。

  通常,唯一約束(或唯一索引)不允許任何種類的重復-如果事務嘗試基於定義為唯一的列創建重復值,那麽事務將被回滾並且拒絕。然而,一旦設置了IGNORE_DUP_KEY選項,就將得到混合的行為。仍然接收錯誤信息,但是錯誤將僅僅是一種警告-記錄仍然沒有被插入。

  從IGNORE_DUP_KEY的角度看,不能會事務進行回滾(錯誤仍是警告錯誤,而不是關鍵錯誤),但重復的行將被拒絕。

  一句話,這個東西的態度是,重復行完全沒問題,但是你要有一個該值的行存在就OK了(插入時,重復行被忽略,還是全部都不允許插入)。

  當你創建唯一索引時,你可以指定IGNORE_DUP_KEY選項,因此本文最開始創建唯一索引的選項可以是:

  CREATE UNIQUE NONCLUSTERED INDEX AK_Product_Name ON Production.Product ( [Name] ) WITH ( IGNORE_DUP_KEY = OFF );

  IGNORE_DUP_KEY這個名字容易讓人誤會。唯一索引存在時重復的值永遠不會被忽略。更準確的說,唯一索引中永遠不允許存在重復鍵。這個選項的作用僅僅是在多列插入時有用。

  比如,你有兩個表,表A和表B,有著完全相同的結構。你可能提交如下語句給SQL Server。

  INSERT INTO TableA SELECT * FROM TableB;

  SQL Server會嘗試將所有表B中的數據插入表A。但如果因為唯一索引拒絕表B中含有和表A相同的數據插入A怎麽辦?你是希望僅僅重復數據插入不成功,還是整個INSERT語句不成功?

  這個取決於你設定的IGNORE_DUP_KEY參數,當你創建唯一索引時,通過設置設個參數可以設定當插入不成功時怎麽辦,設置IGNORE_DUP_KEY的兩種參數解釋如下:

  IGNORE_DUP_KEY=OFF

  整個INSERT語句都不會成功並彈出錯誤提示,這也是默認設置。

  IGNORE_DUP_KEY=OFF

  只有那些具有重復鍵的行不成功,其它所有的行會成功。並彈出警告信息。

  IGNORE_DUP_KEY 選項僅僅影響插入語句。而不會被UPDATE,CREATE INDEX,ALTER INDEX所影響。這個選項也可以在設置主鍵和唯一約束時進行設置。

  7、DROP_EXISTING

  如果指定DROP_EXISTING選項,那麽如果之前已經存在同名索引將在構造新索引之前被刪除。當和群集索引一起使用該選項時,這個選項比簡單刪除並重新創建現有的索引更加有效。如果重新創建與現有索引完全匹配的索引,那麽SQL Server知道它不需要涉及非群集索引,然而為了適應不同的行位置,顯式刪除和創建將導致重新構建所有非群集索引兩次。如果使用DROP_EXISTING改變索引的結構,那麽NCI只被重新構建一次,而不是兩次。

  8、STATISTICS_NORECOMPUTE

  默認情況下,SQL Server試圖自動化在表和索引上更新統計信息的過程。通過選擇該選項,表示將由自己手動負責更新統計信息。為了關閉這個選項,需要運行UPDATESTATISTICS命令,但不使用NORECOMPUTE。

  強烈建議不要使用該選項,因為查詢優化器使用索引上的統計信息來指出索引對於給定的查詢有多大用處。隨著表中數據大量增多或減少,以及列特定值改變。索引上的統計信息會不斷變化。基於這兩點,可以知道不更新統計信息則查詢優化器將基於過時的信息運行查詢,打開自動統計信息功能意味著統計信息將周期地更新(多長時間更新一次取決於對表更新的本質和頻繁程度)。相反關閉自動更新統計信息意味著信息會過時,或者需要設定計劃手動運行UPDATE STATISTICS。

  9、SORT_IN_TEMPDB

  只有在tempdb存儲在與包含新索引的數據庫物理上分離的驅動器上時,該選項才有意義。為什麽?

  當SQL Server建立索引時,它必須執行多個讀操作以處理各種索引構造步驟。

  1、遍歷所有的數據,構建對應於實際數據每一行的葉行。類似於實際數據和最後的索引,這些內容進入用於臨時存儲的頁。這些中間頁不是最終的索引頁,而是每次排序緩沖器已滿時臨時存儲的位置。

  2、通過這些中間頁單獨運行,以將他們合並到最終葉級頁。

  3、當填充葉級頁時,構建非葉級頁。

  如果沒有使用SORT_IN_TEMPDB選項,那麽中間頁將被寫入在其中存儲數據庫的相同物理文件中。這意味著實際數據的讀操作必須與構建過程的寫操作競爭。這兩種情況造成磁頭需要移動到一個不同的位置(讀和寫)。結果是磁頭經常地來回移動-這會花費時間。

  另一方面,如果使用SORT_IN_TEMPDB,那麽中間頁將被寫入tempdb中,而不是數據庫自己的文件。如果它們在單獨的物理驅動器上,這意味著在索引構建的讀和寫操作之間沒有競爭。但是要牢記,只有在tempdb位於與數據庫文件分離的獨立物理驅動器上,這才會有效。否則,只是名義上發生改變,而I/O競爭仍然是問題。

  如果要使用SORT_IN_TEMPDB,那麽確保在tempdb中有用於支持大文件的足夠空間。

  10、ONLINE

  如果將這個選項設置為ON,那麽它將強制表對於一般的訪問保持有效,並且不創建任何阻止用戶使用索引和/表的鎖。默認情況下,全索引操作將獲得所需的鎖(最終得到表鎖),以便對表進行完全和有效的訪問,然而,副作用是這將會阻止用戶(這是矛盾的:一方面可能正在建立索引以使數據庫更為有用,但是同時又使表變得不可用)。

  11、ALLOW ROW/PAGE LOCKS

  這裏的ALLOW設置用於確定索引是否允許行鎖和頁鎖。

  12、MAXDOP

  該選項用於為構建索引覆蓋關於最大並行度的系統設置。並行度是指將有多少個進程用於一個數據庫操作。有一個稱為最大並行度的系統設置,允許限制每個操作中的處理器數。索引創建的MAXDOP選項允許將並行度設置為高於或者低於基本系統設置。只要合適就行。

  13、ON

  SQL Server允許通過使用ON選項將數據和索引單獨存放。這樣做有以下優點:

  •   索引需要的空間可以分散到其他的驅動器中。
  •   用於索引操作的I/O不會加重物理數據檢索的負擔。

下面簡單補充下XML索引的概念。

  XML索引是SQL Server2005新增功能。

  除了IGNORE_DUP_KEY和ONLINE之外,XML的創建語法支持前面的CREATE語句中所看到的所有相同選項。

  在SQL Server中,可以再類型為XML的列上創建索引。這樣做的主要要求如下。

  •   在包含需要索引的XML的表上必須具有群集索引。
  •   在創建“輔助”索引之前,必須先在XML數據列上創建“主”XML索引。
  •   XML索引只能放在XML類型的列上創建(而且XML索引是可以再改類型的列上創建的唯一一種索引)。
  •   XML列必須是基表的一部分-不能在視圖上創建索引。

  1、主XML索引

  在XML索引上創建的第一個索引必須聲明為"主索引"。當創建主索引時,SQL Server創建一個新的群集索引,這個群集索引將基表的群集索引和來自任何指定的XML節點的數據組合在一起。

  2、輔助XML索引

  類似於指向群集索引的群集鍵的非群集索引,輔助XML索引以很相似的方法指向主XML索引。一旦創建了主XML索引,就只能在XML列上創建多達248個以上的XML索引。

二、修改索引

  ALTER INDEX命令在其用來做什麽方面多少有些欺騙性。截止到現在,ALTER命令總是與修改對象的定義有關。例如ALTER表以添加或禁用約束和列。ALTER INDEX是不同的-該命令與維護有關,而與結構完全不相幹。如果需修改索引的組成,那麽只能DROP然後CREATE索引,或者用DROP_EXISTING=ON選項CREATE並使用索引。

  ALTER INDEX的語法類似於下面這樣:

ALTER INDEX {<name of index> | ALL}
ON<table or view name>
{ REBUILD
[[ WITH (
  [PAD_INDEX = {ON | OFF}]
    | [[,] FILLFACTOR = <fillfactor>
    | [[,] SORT_IN_TEMPDB = { ON | OFF }]
    | [[,] IGNORE_DUP_KEY = { ON | OFF }]
    | [[,] STATISTICS_NORECOMPUTE = { ON | OFF }]
    | [[,] ONLINE = { ON| OFF }]
    | [[,] ALLOW_ROW_LOCKS = { ON | OFF }]
    | [[,] ALLOW_PAGE_LOCKS = { ON | OFF }]
    | [[,] MAXDOP = <max degree of parallelism>
  )]
  |[ PARTITION = <partition number>
    [ WITH (< partition rebuild index option>
    [,...N])]]]
    | DISABLE
    | REORGANIZE
    [ PARTITION = <partition number> ]
    [ WITH (LOB_COMPACTION = { ON | OFF })]
    | SET ([ ALLOW_ROW_LOCKS = { ON | OFF} ]
    | [[,] ALLOW_PAGE_LOCKS = { ON | OFF } ]
    | [[,] IGNORE_DUP_KEY = { ON | OFF } ]
    | [[,] STATISTICS_NORECOMPUTE = { ON | OFF }]
  )
}[;]

  其中一些選項與CREATE INDEX命令相同,因此這裏將略過對這些選項的重新定義。除此之外,相當多的ALTER特定選項都是細節性的,且與處理碎片之類的事情有關。下面解釋下參數

  1、索引名

  如果想維護一個特定的索引可以指定該索引,或者使用ALL表明想要維護與指定的表相關聯的所有索引。

  2、表名或視圖名

  要在其上維護的特定對象(表或視圖)的名稱。註意,必須是一個特定的表(可以給它提供一個列表,然後說“請處理所有這些!”)。

  3、REBULD

  如果使用該選項運行ALTER INDEX,那麽將完全丟棄舊的索引並重新生成新的索引。結果是真正優化的索引,其中所有葉級和非葉級的頁都按照定義進行了重新構建。如果是群集索引,那麽也會重新組織物理數據。

  默認情況下,頁將被重新組織為差兩行滿。和CREATE TABLE語法一樣,可以將FILLFACTOR設置為0~100之前的任何值。該值是在數據庫完成重新組織後頁被填滿的程度(以百分比表示)。但在進行頁拆分時,數據將被對半分部在兩個頁上-除了定期重建索引外,不得不斷控制填充的百分比。
  要小心使用該選項,一旦開始REBUILD,在完成索引重建錢,正在使用的索引實際上就沒有了。依賴該索引的所有查詢可能會變得異常慢。對於這類事情,首先需要在離線系統上測試,以了解整個過程將花多少時間。然後,計劃在非高峰時段運行。

  4、DISABLE

  該選項名副其實,只是方式有些過激。如果該命令的全部作用只是為了讓索引離線,直至您決定了進一步要做什麽,則它是不錯的選擇,但它實際會把索引標記為不可用,一旦禁用了某個索引,在重新激活之前,必須重建索引(不是重新組織,而是重建)。

  如果對表禁用了群集索引,那麽也會禁用表。數據仍會保留,但在重建群集索引錢,不能被所有索引(因為他們都依賴群集索引)訪問。

  5、REORGANIZE  
  如果重新組織索引,就得到了比完全重建索引稍遜一點的完全優化,但這種方法可以聯機進行(用戶仍能使用索引)。

  稍遜一點指的是什麽?其實是REORGANIZE只在索引的葉級起作用,而不觸及非葉級。這意味著未獲得完全優化。但是,對於大部分的索引而言,那不是真正產生碎片的地方。

三、刪除索引

  如果不斷地重新分析情況和添加索引,那麽也不要忘記刪除索引。記住在插入索引上的系統開銷。  

  刪除索引的語法如下:

  DROP INDEX <table or view name>.<index name>

SQL Server索引語法 <第四篇>