MSSQL 重建索引(在线重建、控制最大处理器数 、MAXDOP )
一、什么情況下需要重建索引
1、碎片過多(參考值:>20%)
索引碎片如何產生,請移步至《T-SQL查詢高級—SQL Server索引中的碎片和填充因子》
2、填充度過低(參考值:<75%)
導致填充度過低的可能原因:①.有刪除②.有分區表③.聚集索引不是數字④.數據百萬以內,比較少
二、重建索引
ALTER INDEX <name of index> ON <table or view name> REBUILD WITH (ONLINE = ON,MAXDOP = 4)
ONLINE:在線執行,減少重建過程中的鎖(執行時間延長)
MAXDOP:手動配置用于運行索引語句的最大處理器數
| 值 | 說明 |
|---|---|
| 0 |
指定服務器根據當前系統工作負荷確定所使用的 CPU 數目。這是默認值,還是推薦設置。 |
| 1 |
取消生成并行計劃。操作將以串行方式執行。 |
|
2-64 |
將處理器的數量限制為指定的值。根據當前工作負荷,可能使用較少的處理器。如果指定的值大于可用的 CPU 數量,將使用實際可用的 CPU 數量。 |
-- 查找碎片率大于40
SELECT object_name(object_id) ,index_type_desc,alloc_unit_type_desc,avg_fragmentation_in_percent,
fragment_count,avg_fragment_size_in_pages,page_count,record_count,
avg_page_space_used_in_percent
FROM sys.dm_db_index_physical_stats(DB_ID('DBNAME'),
OBJECT_ID(''),NULL,NULL,'Sampled')
WHERE avg_fragmentation_in_percent>40
三、擴展筆記:
對于碎片的解決辦法(引用自:宋沄劍SQL Server索引中的碎片和填充因子)
基本上所有解決辦法都是基于對索引的重建和整理,只是方式不同
1.刪除索引并重建
這種方式并不好.在刪除索引期間,索引不可用.會導致阻塞發生。而對于刪除聚集索引,則會導致對應的非聚集索引重建兩次(刪除時重建,建立時再重建).雖然這種方法并不好,但是對于索引的整理最為有效
2.使用DROP_EXISTING語句重建索引
為了避免重建兩次索引,使用DROP_EXISTING語句重建索引,因為這個語句是原子性的,不會導致非聚集索引重建兩次,但同樣的,這種方式也會造成阻塞
3.如前面文章所示,使用ALTER INDEX REBUILD語句重建索引
使用這個語句同樣也是重建索引,但是通過動態重建索引而不需要卸載并重建索引.是優于前兩種方法的,但依舊會造成阻塞。可以通過ONLINE關鍵字減少鎖,但會造成重建時間加長.
4.使用ALTER INDEX REORGANIZE
這種方式不會重建索引,也不會生成新的頁,僅僅是整理,當遇到加鎖的頁時跳過,所以不會造成阻塞。但同時,整理效果會差于前三種.
當隨著表的數據量不斷增長,很多存儲的數據進行了不適當的跨頁(sqlserver中存儲的最小單位是頁,頁是不不可再分的),會產生很多索引的碎片。這時候需要重建索引來提高查詢性能。
如何查看索引的使用情況:
SELECT index_type_desc,alloc_unit_type_desc,avg_fragmentation_in_percent,fragment_count,avg_fragment_size_in_pages,page_count,record_count,avg_page_space_used_in_percent
FROM sys.dm_db_index_physical_stats(DB_ID('db_name'),OBJECT_ID('table_name),NULL,NULL,'Sampled')
上面的語句是查詢數據庫db_name的表table_name的索引使用情況。
查詢結果中的列avg_fragment_size_in_pages值超過40%就需要重建索引,可以減少IO掃描操作。
重建索引:
alter index pk_my_users on my_users rebuild;
測試結果:
原來的碎片達到89%,重建索引碎片降到2%,查詢速度快了1倍。(數據量為百萬級)
SQL Server索引語法 <第四篇>
從CREATE開始
通過顯式的CREATE INDEX命令
在創建約束時作為隱含的對象
隨約束創建的隱含索引
當向表中添加如下兩種約束之一時,就會創建隱含索引。
主鍵約束(聚集索引)
唯一約束(唯一索引)
一、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>
這樣就可以刪除索引了。
總結
以上是生活随笔為你收集整理的MSSQL 重建索引(在线重建、控制最大处理器数 、MAXDOP )的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: android新架构,Android新架
- 下一篇: 简单选择排序(选择排序)