码迷,mamicode.com
首页 > 其他好文 > 详细

读书笔记:一个非聚集索引查询引起的“表扫描” + “阻塞”问题

时间:2015-08-29 18:26:36      阅读:156      评论:0      收藏:0      [点我收藏+]

标签:

以下是使用AdventureWorks2008R2数据库测试一个因全表扫描而引起的阻塞问题。

步骤:

一、建表

CREATE TABLE Employee_Demo_Heap
(
 [BusinessEntityID] [int] NOT NULL,
 [NationalIDNumber] [nvarchar](15) NOT NULL,
 [LoginID] [nvarchar](256) NOT NULL,
 [OrganizationNode] [hierarchyid] NULL,
 [OrganizationLevel]  AS ([OrganizationNode].[GetLevel]()),
 [JobTitle] [nvarchar](50) NOT NULL,
 [BirthDate] [date] NOT NULL,
 [MaritalStatus] [nchar](1) NOT NULL,
 [Gender] [nchar](1) NOT NULL,
 [HireDate] [date] NOT NULL,
 [SalariedFlag] [dbo].[Flag] NOT NULL,
 [VacationHours] [smallint] NOT NULL,
 [SickLeaveHours] [smallint] NOT NULL,
 [CurrentFlag] [dbo].[Flag] NOT NULL,
 [ModifiedDate] [datetime] NOT NULL,
 CONSTRAINT PK_Employee_BusinessEntityID_Demo_Heap PRIMARY KEY NONCLUSTERED
 (
  BusinessEntityID ASC
 )

)

GO

CREATE NONCLUSTERED INDEX IX_Employee_NationalIDNumber_Demo_Heap ON Employee_Demo_Heap
(
 NationalIDNumber ASC
)

go

CREATE NONCLUSTERED INDEX IX_Employee_ModifiedDate_Demo_Heap ON Employee_Demo_Heap
(
 ModifiedDate ASC
 )

go

insert into Employee_Demo_Heap
(
 BusinessEntityID,
 NationalIDNumber,
 LoginID,
 OrganizationNode,
 JobTitle,
 BirthDate,
 MaritalStatus,
 Gender,
 HireDate,
 SalariedFlag,
 VacationHours,
 SickLeaveHours,
 CurrentFlag,
 ModifiedDate
)
select BusinessEntityID,
 NationalIDNumber,
 LoginID,
 OrganizationNode,
 JobTitle,
 BirthDate,
 MaritalStatus,
 Gender,
 HireDate,
 SalariedFlag,
 VacationHours,
 SickLeaveHours,
 CurrentFlag,
 ModifiedDate
from HumanResources.Employee

go

CREATE NONCLUSTERED INDEX IX_Employee_JobTitle_Demo_Heap ON Employee_Demo_Heap
(
   [JobTitle] ASC
 )

go

 

二、新建连接A中执行以下update语句

begin tran a

  update Employee_Demo_Heap set jobtitle = ‘Changed1‘  where BusinessEntityID = 70

 

三、新建连接B中执行以下select语句

  select BusinessEntityID, loginID, jobtitle from Employee_Demo_Heap where BusinessEntityID in ( 3, 4, 100)

 

发现连接B中的语句已被阻塞住了。查询 select * from sys.dm_tran_locks  发现

对于 RID  1:23128:19     一个连接申请了 X 锁,一个连接申请了 S 锁,S 锁的等待状态是WAIT。

也就是说连接B也对BusinessEntityID = 70这条记录去申请S 锁,但是连接A事务未提交,X 锁未释放。导致被阻塞住了。

但问题是连接B中的select语句并未查询 BusinessEntityID = 70 的记录,为什么还会对 BusinessEntityID = 70 的记录申请 S 锁 呢?

通过对执行计划的分析,我们发现,select BusinessEntityID, loginID, jobtitle from Employee_Demo_Heap where BusinessEntityID in ( 3, 4, 100)  语句采用了 Table Scan ,这就是为什么也会查询 BusinessEntityID = 70 记录的原因了,这也导致了连接B也对BusinessEntityID = 70这条记录去申请S 锁。从而导致了连接B中的语句被阻塞住了。

如果我们把Employee_Demo_Heap的主键 PK_Employee_BusinessEntityID_Demo_Heap  换成聚集索引,再执行连接B中的语句,我们会发现并没有被阻塞。

 

由此,我们可以得到:

  1. 聚集索引容易使用 Clustered Index Seek 从而减少阻塞的概率。
  2. 非聚集索引容易使SQL Server认为非聚集索引+Bookmark Lookup并不比全表扫描快,而采用全表扫描,从而增加阻塞发生的概率。

可见用聚集索引的查询还是比用非聚集索引要可靠的多。能用到聚集索引的地方,我们还是尽量使用聚集索引吧。

读书笔记:一个非聚集索引查询引起的“表扫描” + “阻塞”问题

标签:

原文地址:http://www.cnblogs.com/zhouzx/p/4769215.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!