RPM*_*984 9 sql-server-2008 sql-server
在我们的实时服务器上发生了一些死锁,我知道,这很糟糕。
无论如何,我试图弄清楚如何查看导致锁定(或持有时间过长)的 SQL 代码。
我已经添加了所有的Locks事件(获得、死锁、升级、释放、超时等),但我所看到的只是对获得/释放事件的轰炸,没有太多附加信息。
我很确定我知道导致死锁的“场景”,因为我们在插入/更新/删除后在表上有一个触发器,这做了很多额外的工作,有时高达 8 秒。
但是,在大部分额外工作中,数据从 TableA 中提取并插入到表变量中,大量工作在该表变量的内存中进行(大约 6 秒过去),然后最终插入到 TableB 中。
问题: 即使我只是将某些行选择到表变量中,这实际上会导致整个表的表锁定吗?
我已经添加了“触发跟踪”(插入表 x 值('嗨,我在这里')等),我基本上知道这个过程花费的时间最长(因此必须可能导致锁定?)
但我仍然不确定为什么会发生僵局。
问题: 我可以看到发生了 2 个锁升级,这是否意味着行锁已升级为表锁?
问题: 有人能给我一些关于如何进一步追踪这个僵局的提示吗?
编辑:
这是死锁图
编辑2:
这是 [UpdatePostsCleanedUriUniqueUri] 的代码,这可能会导致表锁定?
ALTER PROC [dbo].[UpdatePostsCleanedUriUniqueUri]
(
@PostIds IdentityType READONLY
)
AS
SET NOCOUNT ON
-- *************************************************************************
-- ******************* Create the Cleaned Uri's, first ********************
-- *************************************************************************
---- "Remove" any existing cleaned uri's, per location
UPDATE a
SET a.CleanedUri = NEWID(),
a.UniqueUri = NEWID()
FROM [dbo].[Posts] a
INNER JOIN @PostIds b ON a.PostId = b.Id
-- ** Now add the cleaned uri.
UPDATE a
SET a.CleanedUri = [dbo].[ToFixedLengthToString](
[dbo].[IsNullOrEmpty](LOWER([dbo].[ToAlphaNumericText]([Subject], '-', 1)), 'unknown'), 60, '')
FROM [dbo].[Posts] a
INNER JOIN @PostIds b ON a.PostId = b.Id
-- *************************************************************************
-- ******** Now create the Unique Uri from the cleaned one, above **********
-- *************************************************************************
-- Now Re-Add these unique uri's.
;WITH CTE AS (
SELECT DISTINCT CleanedUri
FROM [dbo].[Posts] a
INNER JOIN @PostIds b ON a.PostId = b.Id
)
UPDATE a
SET a.UniqueUri = Result.UniqueUri
FROM [dbo].[Posts] a
INNER JOIN (
SELECT SubQuery.PostId,
CASE SubQuery.RowNumber
WHEN 1 THEN SubQuery.CleanedUri
ELSE SubQuery.CleanedUri + '-' + CAST(SubQuery.RowNumber - 1 AS NVARCHAR(20)) END AS UniqueUri
FROM (
SELECT PostId, a.CleanedUri,
ROW_NUMBER() OVER (PARTITION BY a.CleanedUri ORDER BY a.CleanedUri) AS RowNumber
FROM [dbo].[Posts] a
INNER JOIN CTE b ON a.CleanedUri = b.CleanedUri
) SubQuery
) Result ON a.PostId = Result.PostId
;
Run Code Online (Sandbox Code Playgroud)
因为它有一个 INNER JOIN,我会认为它只会锁定匹配的行?或者我应该使用WITH (ROWLOCK)
?
编辑 3:
USE [XWing]
GO
/****** Object: Table [dbo].[Posts] Script Date: 02/17/2012 13:29:05 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
SET ANSI_PADDING ON
GO
CREATE TABLE [dbo].[Posts](
[PostId] [int] IDENTITY(1,1) NOT NULL,
[Subject] [nvarchar](300) NULL,
[CleanedUri] [nvarchar](70) NOT NULL,
[UniqueUri] [nvarchar](70) NOT NULL,
[Content] [nvarchar](max) NULL,
[Source] [nvarchar](50) NULL,
[LocationTypeId] [tinyint] NOT NULL,
[CreatedOn] [smalldatetime] NOT NULL,
[ModifiedOn] [smalldatetime] NOT NULL,
[IsEditorsChoice] [bit] NOT NULL,
[IsVisible] [bit] NOT NULL,
[UserId] [int] NOT NULL,
[LatLongPoint] [geography] NULL,
[UserLastIpAddress] [varchar](15) NULL,
[OldPostId] [int] NULL,
[OldUniqueUri] [nvarchar](250) NULL,
[ThemeId] [int] NOT NULL,
CONSTRAINT [PK_Posts] PRIMARY KEY CLUSTERED
(
[PostId] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, FILLFACTOR = 90) ON [PRIMARY]
) ON [PRIMARY]
GO
SET ANSI_PADDING OFF
GO
ALTER TABLE [dbo].[Posts] WITH CHECK ADD CONSTRAINT [FK_Posts_Themes] FOREIGN KEY([ThemeId])
REFERENCES [dbo].[Themes] ([ThemeId])
GO
ALTER TABLE [dbo].[Posts] CHECK CONSTRAINT [FK_Posts_Themes]
GO
ALTER TABLE [dbo].[Posts] WITH CHECK ADD CONSTRAINT [FK_Posts_Users] FOREIGN KEY([UserId])
REFERENCES [dbo].[Users] ([UserId])
GO
ALTER TABLE [dbo].[Posts] CHECK CONSTRAINT [FK_Posts_Users]
GO
ALTER TABLE [dbo].[Posts] ADD CONSTRAINT [DF_Posts_IsEditorsChoice] DEFAULT ((0)) FOR [IsEditorsChoice]
GO
ALTER TABLE [dbo].[Posts] ADD CONSTRAINT [DF_Posts_ThemeId] DEFAULT ((1)) FOR [ThemeId]
GO
USE [XWing]
GO
/****** Object: Index [IX_Posts_IsEditorsChoice_Include_PostId_LocationTypeId] Script Date: 02/17/2012 13:31:59 ******/
CREATE NONCLUSTERED INDEX [IX_Posts_IsEditorsChoice_Include_PostId_LocationTypeId] ON [dbo].[Posts]
(
[IsEditorsChoice] ASC
)
INCLUDE ( [PostId],
[LocationTypeId]) WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, FILLFACTOR = 90) ON [PRIMARY]
GO
USE [XWing]
GO
/****** Object: Index [IX_Posts_IsVisible] Script Date: 02/17/2012 13:32:02 ******/
CREATE NONCLUSTERED INDEX [IX_Posts_IsVisible] ON [dbo].[Posts]
(
[IsVisible] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, FILLFACTOR = 90) ON [PRIMARY]
GO
USE [XWing]
GO
/****** Object: Index [IX_Posts_LocationTypeId] Script Date: 02/17/2012 13:32:07 ******/
CREATE NONCLUSTERED INDEX [IX_Posts_LocationTypeId] ON [dbo].[Posts]
(
[LocationTypeId] ASC
)
INCLUDE ( [PostId]) WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, FILLFACTOR = 90) ON [PRIMARY]
GO
USE [XWing]
GO
/****** Object: Index [IX_Posts_OldPostId] Script Date: 02/17/2012 13:32:12 ******/
CREATE NONCLUSTERED INDEX [IX_Posts_OldPostId] ON [dbo].[Posts]
(
[OldPostId] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, FILLFACTOR = 90) ON [PRIMARY]
GO
USE [XWing]
GO
/****** Object: Index [IX_Posts_UserId] Script Date: 02/17/2012 13:32:17 ******/
CREATE NONCLUSTERED INDEX [IX_Posts_UserId] ON [dbo].[Posts]
(
[UserId] ASC
)
INCLUDE ( [PostId]) WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, FILLFACTOR = 90) ON [PRIMARY]
GO
USE [XWing]
GO
/****** Object: Index [SX_Posts_Location] Script Date: 02/17/2012 13:32:22 ******/
CREATE SPATIAL INDEX [SX_Posts_Location] ON [dbo].[Posts]
(
[LatLongPoint]
)USING GEOGRAPHY_GRID
WITH (
GRIDS =(LEVEL_1 = LOW,LEVEL_2 = LOW,LEVEL_3 = MEDIUM,LEVEL_4 = HIGH),
CELLS_PER_OBJECT = 16, PAD_INDEX = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
GO
USE [XWing]
GO
/****** Object: Index [UIX_Posts_UniqueUri] Script Date: 02/17/2012 13:32:41 ******/
CREATE UNIQUE NONCLUSTERED INDEX [UIX_Posts_UniqueUri] ON [dbo].[Posts]
(
[UniqueUri] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, FILLFACTOR = 80) ON [PRIMARY]
GO
Run Code Online (Sandbox Code Playgroud)
编辑 4
这是为 CleanedUri添加以下索引后UpdatePostsCleanedUriUniqueUri 的执行计划:
CREATE NONCLUSTERED INDEX [IX_Posts_CleanedUri_Include_PostId] ON [dbo].[Posts]
(
[CleanedUri] ASC
)
INCLUDE ( [PostId]) WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
GO
Run Code Online (Sandbox Code Playgroud)
Rem*_*anu 14
即使我只是将某些行选择到表变量中,这实际上会导致整个表的表锁定吗?
锁定升级。如果您的“选择”不是......选择性的,如果它必须扫描表的大部分,那么引擎可能会升级为表锁。请参阅锁升级(数据库引擎)。
我可以看到发生了 2 个锁升级,这是否意味着行锁已升级为表锁?
他们是锁定升级事件,还是只是锁定升级尝试?如果成功,则事务已锁定整个表。
有人能给我一些关于如何进一步追踪这个僵局的提示吗?
从单独的锁 POV 来解决这个问题并不是很有成效。典型的调查侧重于捕获和分析死锁图。请参阅使用 SQL Server Profiler 分析死锁。捕获死锁图并将其张贴在这里,也许我们可以提供帮助。上传死锁图XML,而不是死锁的图片,请参阅如何:保存死锁图 (SQL Server Profiler)。
死锁图:
Spid 58 在 IX 模式下具有页面 7:1:11066,并且正在阻止希望它在 S 模式下使用的 spid 61。Spid 61 的页面 7:1:1932345 处于 S 模式,并且正在阻止 spid 58 上有 IU 模式锁定但希望将其转换为 IX。由于增加了并行性和一长串“我也是”服务员,事情变得复杂了,但基本问题可以简化为我上面描述的问题。
这是典型的索引缺失模式。您有一个更新程序,XWingNew.dbo.UpdatePostsCleanedUriUniqueUri
它发出可能扫描整个XWingNew.dbo.Posts
表的更新。同时,您有几个读者可能也在一些 linq 生成的查询中扫描整个表,这些查询在 XML: 中被截断SELECT [UnionAll3].[C2] AS [C1], [UnionAll3].[C3] AS [C2], [UnionAll3].[C4] AS [C3], [UnionAll3].[C5] AS [C4],...
。因为更新和选择发出表扫描,当更新尝试将它在扫描阶段获得的 IU 页锁转换为更新合格行所需的 IX 锁时,它们几乎可以保证死锁。
您现在有两种选择: