鎖
鎖的模式
| 鎖模式 |
描述 |
| 共享(S) |
用於不更改或不更新數據(只讀操作),如SELECT語句 |
| 更新(U) |
用於可更新的資源中。防止當多個會話在讀取、鎖定以及隨后可能進行的資源更新時發生常見形式的死鎖。 |
| 排它(X) |
用於數據修改操作,例如INSERT、UPDATE或DELETE。確保不會同時對同一資源進行多重更新 |
| 意向 |
SQL Server有在資源的低層獲得共享鎖或排它鎖的意向意向鎖的類型為:意向共享(IS)、意向排它(IX)以及意向排它共享(SIX) |
| 架構 |
在執行依賴於表架構的操作時使用。架構鎖的類型為:架構修改(Sch-M)和架構穩定(Sch-S) |
| 大容量更新(BU) |
向表中大容量復制數據並指定了TABLOCK提示時使用 |
死鎖 死鎖是指在一組進程中的各個進程均占有不會釋放的資源,但因互相申請被其他進程所站用不會釋放的資源而處於的一種永久等待狀態。
死鎖的四個必要條件
互斥條件(Mutual exclusion):資源不能被共享,只能由一個進程使用。
請求與保持條件(Hold and wait):已經得到資源的進程可以再次申請新的資源。
非剝奪條件(No pre-emption):已經分配的資源不能從相應的進程中被強制地剝奪。
循環等待條件(Circular wait):系統中若干進程組成環路,該環路中每個進程都在等待相鄰進程正占用的資源
死鎖的處理方法
查看那個spid處於wait狀態,然后用kill spid來干掉(即破壞死鎖的第四個必要條件:循環等待)。
使用SET LOCK_TIMEOUT timeout_period(單位為毫秒)來設定鎖請求超時。默認情況下,數據庫沒有超時期限(timeout_period值為-1,可以用SELECT @@LOCK_TIMEOUT來查看該值,即無限期等待)。
SQL Server內部有一個鎖監視器線程執行死鎖檢查,鎖監視器對特定線程啟動死鎖搜索,檢測到死鎖后,數據庫引擎選擇運行回滾開銷最小的事務的會話作為死鎖犧牲品回滾死鎖犧牲品的事務並釋放該事務持有的所有鎖,使其他線程的事務可以請求資源並繼續運行。
游標
游標定義:
可以對一個select的結果集進行處理,或是不需要全部處理,就會返回一個對記錄集進行處理之后的結果。
游標實際上是一種能從多條數據記錄的結果集中每次提取一條記錄的機制。游標可以完成:
# 允許定位到結果集中的特定行
# 從結果集的當前位置檢索一行或多行數據
# 支持對結果集中當前位置的進行修改
由於游標是將記錄集進行一條條的操作,所以這樣給服務器增加負擔,一般在操作復雜的結果集的情況下,才使用游標。SQL Server 2005有三種游標:T-SQL游標、API游標、客戶端游標。
游標的基本操作
游標的基本操作有定義游標、打開游標、循環讀取游標、關閉游標、刪除游標。
A、 定義游標
declare cursor_name --游標名稱 cursor [local | global] --全局、局部 [forward only | scroll] --游標滾動方式 [read_only | scroll_locks | optimistic] --讀取方式 for select_statements --查詢語句 [for update | of column_name ...] --修改字段
參數:
forward only | scroll:前一個參數,游標只能向后移動;后一個參數,游標可以隨意移動
read_only:只讀游標
scroll_locks:游標鎖定,游標在讀取時,數據庫會將該記錄鎖定,以便游標完成對記錄的操作
optimistic:該參數不會鎖定游標;此時,如果記錄被讀入游標后,對游標進行更新或刪除不會超過
B、 打開游標
open cursor_name;
游標打開后,可以使用全局變量@@cursor_rows顯示讀取記錄條數
C、 檢索游標
fetch cursor_name;
檢索方式如下:
fetch first; 讀取第一行
fetch next; 讀取下一行
fetch prior; 讀取上一行
fetch last; 讀取最后一行
fetch absolute n; 讀取某一行
如果n為正整數,則讀取第n條記錄
如果n為負數,則倒數提取第n條記錄
如果n為,則不讀取任何記錄
fetch pelative n
如果n為正整數,則讀取上次讀取記錄之后第n條記錄
如果n為負數,則讀取上次讀取記錄之前第n條記錄
如果n為,則讀取上次讀取的記錄
D、 關閉游標
close cursor_name;
E、 刪除游標
deallocate cursor_name;
游標操作示例
--創建一個游標 declare cursor_stu cursor scroll for select id, name, age from student; --打開游標 open cursor_stu; --存儲讀取的值 declare @id int, @name nvarchar(20), @age varchar(20); --讀取第一條記錄 fetch first from cursor_stu into @id, @name, @age; --循環讀取游標記錄 print '讀取的數據如下:'; --全局變量 while (@@fetch_status = 0) begin print '編號:' + convert(char(5), @id) + ', 名稱:' + @name + ', 類型:' + @age; --繼續讀取下一條記錄 fetch next from cursor_stu into @id, @name, @age; end --關閉游標 close area_cursor; --刪除游標 --deallocate area_cursor;
索引
聚集索引定義:
聚簇索引即建立在聚簇上的索引,創建聚簇索引時,需要對已有表數據重新進行排序(若表中已有數據),即刪除原始的表數據后再將排序結果按物理順序插回,故聚簇索引建立完畢后,建立聚簇索引的列中的數據已經全部按序排列。
一個表中只能包含一個聚簇索引,但該索引可以包含多個列。
B-樹索引中,聚簇索引的葉層就是數據頁。
聚集索引最佳實踐:
首先創建聚集索引
聚集索引鍵最好是唯一值
聚集索引上的列需要足夠短,檢索一定范圍和預先排序數據時使用,因為聚集索引的葉子與數據頁面相同,索引順序也是數據物理順序,讀取數據時,磁頭是按照順序讀取,而不是隨機定位讀取數據
在頻繁更新的列上不要設計聚集索引,他將導致所有的非聚集所有的更新,阻塞非聚集索引的查詢
不要使用太長的關鍵字,因為非聚集索引實際包含了聚集索引值
不要在太多並發度高的順序插入,這將導致頁面分割,設置合理的填充因子是個不錯的選擇
聚集索引示例:
CREATE CLUSTERED INDEX IX_tb_heap_test_id ON dbo.tb_heap_test (id) WITH (ONLINE=ON)
非聚集索引定義:
非聚簇索引類似書本索引,索引與數據存放在不同的物理區域,建立非聚簇索引時數據本身不進行排序。一個表中科含多個非聚簇索引。
B-樹索引中,非聚簇索引的葉層仍是索引頁,其以指針指向數據頁實際存儲位置。
非聚集索引最佳實踐
頻繁更新的列,不適合做聚集索引,但可以做非聚集索引
寬關鍵字,例如很寬的一列或者一組列,不適合做聚集索引的列可作非聚集索引列
檢索大量的行不宜做非聚集索引,但是可以使用覆蓋索引來消除這種影響
非聚集索引示例:
CREATE INDEX IX_tb_clustered_update_ID ON dbo.tb_clustered_update (ID) WITH (ONLINE=ON)
非聚集與聚集用法之比較
檢索的數據行
一般地,檢索數據量大的一般使用聚集索引,因為聚集索引的葉子頁面與數據頁面在相同。相反,檢索少量的數據可能非聚集索引更有利,但注意書簽查找消耗資源的力度,不過可考慮覆蓋索引解決這個問題。
數據是否排序
如果數據需要預先排序,需要使用聚集索引,若不需要預先排序就那就選擇聚集索引。
索引鍵的寬度
索引鍵如果太寬,不僅會影響數據查詢性能,還影響非聚集索引,因此,若索引鍵比較小,可以作為聚集索引,如果索引鍵夠大,考慮非聚集索引,如果很大的話,可以用INCLUDE創建覆蓋索引
列更新的頻度
列更新頻率高的話,應該避免考慮所用非聚集索引,否則可考慮聚集索引。
書簽查找開銷
如果書簽查找開銷較大,應該考慮聚集索引,否則可使用非聚集索引,更佳是使用覆蓋索引,不過得根據具體的查詢語句而看
覆蓋索引
覆蓋索引可顯著減少查詢的邏輯讀次數,使用INCLUDE語句添加列的方式更容易實現,他不僅減小索引中索引列的數據,還可以減少索引鍵的大小,原因是包含列只保存在索引的葉子級別上,而不是索引的葉子頁面。覆蓋索引充當一個偽的聚集索引。覆蓋索引還能夠有效的減少阻塞和死鎖的發生,與聚集索引類似,因為聚集索引值發生一次鎖,非覆蓋索引可能發生兩次,一次鎖數據,一次鎖索引,以確保數據的一致性。覆蓋索引相當於數據的一個拷貝,與數據頁面隔離,因此也只發生一次鎖。
覆蓋索引示例:
CREATE INDEX IX_IX_tb_booklookup_name_type_other ON dbo.tb_booklookup (name) INCLUDE ([type],other) WITH ( ONLINE=ON )
