use XTS
--步驟一=============創建測試表===================================================
--測試表1
if(exists(select 1 from sysobjects where id=OBJECT_ID('testa')))
drop table testa
CREATE TABLE testa
(
id int primary key,--Id,並標記爲主建
name varchar(10),--姓名
age decimal(26,4),--年齡
city varchar(10),--所在城市
address varchar(10),--家庭地址
remark text --備註
)
--創建非聚集索引
create unique nonclustered index testa_idx1 on testa(name,age)
--測試表2
if(exists(select 1 from sysobjects where id=OBJECT_ID('testb')))
drop table testb
CREATE TABLE testb
(
id int primary key,--Id,並標記爲主建
name varchar(10),--姓名
age decimal(26,4),--年齡
city varchar(10),--所在城市
address varchar(10),--家庭地址
remark text --備註
)
--創建非聚集索引
create unique nonclustered index testb_idx1 on testb(name,age)
--步驟二===================添加測試數據================================================
insert into testa(id,name,age,city,address)
select 1,'joe',20,'hz','zjwz'
insert into testa(id,name,age,city,address)
select 2,'jill',25,'hz','zjhz'
insert into testa(id,name,age,city,address)
select 3,'Bob',27,'hz','zjhz'
insert into testb(id,name,age,city,address)
select 1,'joe',20,'hz','zjwz'
insert into testb(id,name,age,city,address)
select 2,'jill',25,'hz','zjhz'
insert into testb(id,name,age,city,address)
select 3,'Bob',27,'hz','zjhz'
--添加多一點,是爲了查詢效率降低,以便快速得到驗證結果
declare @i int=4
while (@i<1000)
begin
insert into testa(id,name,age,city,address)
select @i,@i,27,'xxxx','xxxx'
set @i=@i+1
end
--步驟三===================創建測試存儲過程及備用表================================================
IF OBJECT_ID ('p1') IS NOT NULL DROP PROC p1
IF OBJECT_ID ('p2') IS NOT NULL DROP PROC p2
--創建備份表,用於查詢存儲過程的結果存儲
if(exists(select 1 from sysobjects where id=OBJECT_ID('testback')))
drop table testback
CREATE TABLE testback
(
id int primary key,--Id,並標記爲主建
name varchar(10),--姓名
age decimal(26,4),--年齡
city varchar(10),--所在城市
address varchar(10)--家庭地址
)
if(exists(select 1 from sysobjects where id=OBJECT_ID('testback1')))
drop table testback1
CREATE TABLE testback1
(
id int primary key,--Id,並標記爲主建
name varchar(10),--姓名
age decimal(26,4),--年齡
city varchar(10),--所在城市
address varchar(10)--家庭地址
)
if(exists(select 1 from sysobjects where id=OBJECT_ID('testback2')))
drop table testback2
CREATE TABLE testback2
(
id int primary key,--Id,並標記爲主建
name varchar(10),--姓名
age decimal(26,4),--年齡
city varchar(10),--所在城市
address varchar(10)--家庭地址
)
--創建存儲過程p1,更新存儲過程
CREATE PROC p1 AS
UPDATE testa SET age = age+1 WHERE id = 1
UPDATE testa SET age = age-1 WHERE id = 1
GO
--創建存儲過程p2,查詢存儲過程
CREATE PROC p2 AS
truncate table testback
insert into testback(id,name,age,address)
select id,name,age,address from testa where name='joe'
GO
---死鎖案例一============兩個事物各佔有自己的資源,同時又需要對方的資源==================
--查詢一
begin transaction
update a set address='TT' from testa a where id=1
waitfor delay '00:00:10'
select * from testb where id=1
commit transaction
--查詢二
begin transaction
update a set address='TT' from testb a where id=1
waitfor delay '00:00:10'
select * from testa where id=1
commit transaction
--死鎖案例二============書籤查詢引起的死鎖=============================================
--高頻率update
while (1=1) exec p1
--高頻率select
while (1=1) exec p2
Set statistics profile off
UPDATE testa SET age = age+1 WHERE id = 1
select id,name,age,address from testa where name='joe'
--死鎖三================在較高隔離級別的事務中,兩個事務同時執行查詢及更新語句============
--查詢事務一
--需要設置事務隔離級別可重複瀆或加事務保持鎖
SET TRANSACTION ISOLATION LEVEL Repeatable read
while(1=1)
begin
begin transaction
truncate table testback1
insert into testback1(id,name,age,address)
select id,name,age,address from testa where id=1
waitfor delay '00:00:10'
update testa set age=age+1 where id=1
update testa set age=age-1 where id=1
commit transaction
end
--查詢事務二
SET TRANSACTION ISOLATION LEVEL Repeatable read
while(1=1)
begin
begin transaction
truncate table testback2
insert into testback2(id,name,age,address)
select id,name,age,address from testa where id=1
waitfor delay '00:00:10'
update testa set age=age+1 where id=1
update testa set age=age-1 where id=1
commit transaction
end
--死鎖四===========同一個表當兩個事務都在更新不同的記錄時,即使沒有更新索上的字段,
--也會引起死鎖,因爲查詢的字段沒有全部在所建的普通索引上面,所以同樣需要通過聚集索引做全表查詢
--但是聚集索引上的行在同一時間點上被不同事務在擁有,這樣就造成了兩個事務查詢的時候都無法獲取
--全部的資源,即造成了死鎖
--測試數據如下
drop table testx
create table testx(id int primary key,name varchar(10),age int)
create index testx_ind1 on testx(name)
insert into testx(id,name,age)
select '1','袁*','22'
insert into testx(id,name,age)
select '2','程*','20'
create table testx1(id int primary key,name varchar(10),age int)
create table testx2(id int primary key,name varchar(10),age int)
--查詢一
while(1=1)
begin
begin transaction
update testx set age=age+1 where name='程*'
truncate table testx1
insert into testx1(id,name,age)
select id,name,age from testx where name='程*'
commit transaction
end
--查詢二
while(1=1)
begin
begin transaction
update testx set age=age+1 where name='袁*'
truncate table testx2
insert into testx2(id,name,age)
select id,name,age from testx where name='袁*'
commit transaction
end
--那你們可能就會有疑問,那我是不是單純更新,不做查詢的時候也會死鎖?因爲更新如果也是通過非主鍵字段更新時,也是全表掃描。
--答案:不會,至於爲什麼不會,我們只能理解數據庫本身在更新和查詢時上鎖的原理不一樣,這個我們也可以做個測試例子。
--查詢一=====事務A更新20秒後結束
begin transaction
update testx set age=40 where name='程*'
waitfor delay '00:00:20'
commit transaction
--查詢二======事務B在5秒後結束
begin transaction
update testx set age=40 where name='袁*'
waitfor delay '00:00:05'
commit transaction
--查詢三====再分開執行下面兩個查詢
select * from testx where name='袁*'
select * from testx where name='程*'
--測試結果:
--當我們依次執行查詢一,再執行查詢二,最後執行查詢三:
--結果就是查詢二5秒後(不需要等待查詢一完成)就執行完成了,而查詢三無論執行那個查詢語句都需要等待20秒後(即必須要等待查詢一完成)才能出來查詢查詢結果
--結論就是更新和查詢時上鎖原理不一樣。
--=================隔離級別的演示=============================
DBCC USEROPTIONS
--未提交讀(Read uncommitted)演示
--查詢一
SET TRANSACTION ISOLATION LEVEL Read uncommitted
select * from testa where id=100
begin transaction
update testa set city='newxx' where id=100
waitfor delay '00:00:10'
rollback transaction
--查詢二
SET TRANSACTION ISOLATION LEVEL Read uncommitted
select * from testa where id=100
--已提交讀(Read committed)也叫不可重複瀆
--查詢一
SET TRANSACTION ISOLATION LEVEL Read committed
select * from testa where id=100
begin transaction
update testa set city='newx' where id=100
waitfor delay '00:00:10'
rollback transaction
--查詢二
SET TRANSACTION ISOLATION LEVEL Read committed
select * from testa where id=100
--可重複讀(Repeatable read)演示(保證在同一個事務中,瀆取數據不會被其他事務更改)
--查詢一
SET TRANSACTION ISOLATION LEVEL Repeatable read
begin transaction
select * from testa where id=100
waitfor delay '00:00:10'
commit transaction
--查詢二
SET TRANSACTION ISOLATION LEVEL Repeatable read
update testa set city='new' where id=100
--可序列化演示(事務的最高級別,保證事務的串行執行)
--查詢一
SET TRANSACTION ISOLATION LEVEL Serializable
begin transaction
select * from testa
update testa set city='new' where id=100
waitfor delay '00:00:10'
select * from testa
commit transaction
--查詢二
SET TRANSACTION ISOLATION LEVEL Serializable
insert into testa(id,name,age,city,address)
select 4000,'Bobx',27,'hz','zjhz'
--創建覆蓋索引
drop index testa_idx1 on testa
create index testa_idx1 on testa(name,age) include(id,address)
--設置隔離級別爲可重複瀆
SET TRANSACTION ISOLATION LEVEL Repeatable read
DBCC USEROPTIONS
--開啓事務隔離的方法
declare @sql varchar(8000)
select @sql = '
ALTER DATABASE ' + DB_NAME() + ' SET SINGLE_USER WITH ROLLBACK IMMEDIATE ;
ALTER DATABASE ' + DB_NAME() + ' SET TRANSACTION ISOLATION LEVEL read committed;
ALTER DATABASE ' + DB_NAME() + ' SET MULTI_USER;'
Exec(@sql)
--查詢事務隔離
DBCC Useroptions
--清除緩存
DBCC DROPCLEANBUFFERS
DBCC FREEPROCCACHE
DBCC FREESYSTEMCACHE('ALL')
--開啓SQL性能分析
Set statistics profile on
--開啓SQL執行時間統計
set statistics time ON
--開啓磁盤的讀寫統計
set statistics io on
--鎖查詢相關
SELECT request_session_id, resource_type, resource_associated_entity_id,
request_status, request_mode, resource_description
FROM sys.dm_tran_locks
select request_session_id spid,OBJECT_NAME(resource_associated_entity_id) tableName
from sys.dm_tran_locks where resource_type='OBJECT'
sp_lock
sp_who
select * from sys.sysprocesses
dbcc inputbuffer(spid)
SQL常見死鎖例子及分析
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.