小编Pau*_*ams的帖子

不同进程中相同临时表上的锁导致的死锁

我发现了一个僵局,似乎表明了我认为不可能的事情。死锁涉及两个进程:

1. process8cf948 SPID 63

  • 对临时表 #PB_Cost_Excp_Process_Invoices_Work 执行 ALTER TABLE。

  • 拥有表 #PB_Cost_Excp_Process_Invoices_Work 的 IX 锁,对象 ID 为 455743580

2. process4cb3708 SPID 72

  • 在临时表 #PB_Cost_Excp_Process_Invoices_Work 上执行更新,它应该是它自己唯一的表副本。

  • 在#PB_Cost_Excp_Process_Invoices_Work 上拥有 Sch-M 锁,对象 ID 为 455743580

这应该是不可能的。我错过了什么吗?#Temporary 表真的在这两个 SPID 之间重用了吗?

这是在 SQL Server 2008 R2 Service Pack 2 和累积更新 1(版本 10.50.4260)上。

完整的未更改死锁跟踪如下。请注意这两个进程如何在具有相同表名的相同对象 ID 上运行 #PB_Cost_Excp_Process_Invoices_Work_SNIP_0000000D8519:

12/14/2012 13:46:03,spid23s,Unknown,waiter id=process8cf948 mode=X requestType=wait
12/14/2012 13:46:03,spid23s,Unknown,waiter-list
12/14/2012 13:46:03,spid23s,Unknown,owner id=process4cb3708 mode=Sch-M
12/14/2012 13:46:03,spid23s,Unknown,owner-list
12/14/2012 13:46:03,spid23s,Unknown,objectlock lockPartition=0 objid=455743580 subresource=FULL dbid=2 objectname=tempdb.dbo.#PB_Cost_Excp_Process_Invoices_Work_________________________________________________________________________________0000000D8519 id=lock371705d00 mode=Sch-M associatedObjectId=455743580
12/14/2012 13:46:03,spid23s,Unknown,waiter id=process4cb3708 mode=Sch-M …
Run Code Online (Sandbox Code Playgroud)

sql-server-2008 sql-server deadlock

18
推荐指数
1
解决办法
1万
查看次数

LATCH_EX 等待资源 METADATA_SEQUENCE_GENERATOR

我们有一个生成库存报告的流程。在客户端,进程拆分可配置数量的工作线程,为报告构建一个数据块,该数据块对应于许多商店中的一个(可能是数千个,通常是数十个)。每个工作线程调用一个执行存储过程的 Web 服务。

处理每个块的数据库进程将一堆数据收集到一个#Temporary 表中。在每个处理块结束时,数据将写入 tempdb 中的永久表。最后,在进程结束时,客户端的一个线程从永久 tempdb 表中请求所有数据。

运行此报告的用户越多,它的速度就越慢。我分析了数据库中的活动。有一次,我看到 35 个单独的请求在过程中的某一点都被阻止了。所有这些 SPIDLATCH_EX对资源类型的等待时间大约为 50 毫秒METADATA_SEQUENCE_GENERATOR (00000010E13CA1A8)。一个 SPID 拥有此资源,而所有其他 SPID 都处于阻塞状态。我在网络搜索中没有找到有关此等待资源的任何信息。

我们正在使用的 tempdb 中的表确实有一IDENTITY(1,1)列。这些 SPID 是否在等待 IDENTITY 列?我们可以使用哪些方法来减少或消除阻塞?

服务器是集群的一部分。服务器在 64 位 Windows 2008 R2 Enterprise 上运行 64 位 SQL Server 2012 Standard Edition SP1。服务器有 64 GB RAM 和 48 个处理器,但数据库只能使用 16 个,因为它是标准版。

(请注意,我对在 tempdb 中使用永久表来保存所有这些数据的设计并不感到兴奋。改变这将是一个有趣的技术和政治挑战,但我愿意接受建议。)

更新 4/23/2013

我们已经与 Microsoft 建立了一个支持案例。随着我们了解更多,我会更新这个问题。

更新 5/10/2013

SQL Server 支持工程师同意等待是由 IDENTITY 列引起的。删除 IDENTITY 消除了等待。我们无法在 SQL 2008 R2 上复制该问题;它仅发生在 SQL 2012 …

sql-server concurrency sql-server-2012 wait-types

11
推荐指数
2
解决办法
3218
查看次数

将几行插入大表时性能缓慢

我们有一个从商店获取数据并更新公司范围内的库存表的流程。该表按日期和按项目为每个商店提供行。对于拥有许多商店的客户,该表可能会变得非常大——大约有 5 亿行。

当商店输入数据时,此库存更新过程通常每天运行多次。这些运行仅从少数商店更新数据。但是,客户也可以运行此程序来更新过去 30 天内的所有商店。在这种情况下,该过程启动 10 个线程并在单独的线程中更新每个商店的库存。

客户抱怨这个过程需要很长时间。我分析了这个过程,发现插入到这个表中的一个查询消耗的时间比我预期的要多得多。此 INSERT 有时会在 30 秒内完成。

当我对这个表(由 BEGIN TRAN 和 ROLLBACK 限定)运行 ad-hoc SQL INSERT 命令时,ad-hoc SQL 以毫秒的数量级完成。

执行缓慢的查询如下。这个想法是插入不存在的记录,然后在我们计算各种数据位时更新它们。该过程的前一个步骤已确定需要更新的项目,进行一些计算,并将结果填充到 tempdb 表 Update_Item_Work 中。这个进程在 10 个独立的线程中运行,每个线程在 Update_Item_Work 中有自己的 GUID。

INSERT INTO Inventory
(
    Inv_Site_Key,
    Inv_Item_Key,
    Inv_Date,
    Inv_BusEnt_ID,
    Inv_End_WtAvg_Cost
)
SELECT DISTINCT
    UpdItemWrk_Site_Key,
    UpdItemWrk_Item_Key,
    UpdItemWrk_Date,
    UpdItemWrk_BusEnt_ID,
    (CASE UpdItemWrk_Set_WtAvg_Cost WHEN 1 THEN UpdItemWrk_WtAvg_Cost ELSE 0 END)
FROM tempdb..Update_Item_Work (NOLOCK)
WHERE UpdItemWrk_GUID = @GUID
AND NOT EXISTS
    -- Only insert for site/item/date combinations that don't exist
    (SELECT …
Run Code Online (Sandbox Code Playgroud)

performance sql-server query-performance

9
推荐指数
1
解决办法
2万
查看次数

无法在扩展事件会话中观看实时数据

我在我的 PC 上运行 SQL Server 2014 Developer Edition。我正在尝试查看 system_health 会话中的数据。在SSMS中,我已经连接到数据库,扩展了服务器/管理/扩展事件/会话。我看到 AlwaysON_health(停止)和 system_health(运行)。

当我右键单击 system_health 会话时,出现以下错误:

使用提供的参数初始化存储失败。(Microsoft.SqlServer.XEventStorage) 找不到名为“system_health”的扩展事件会话。确保会话存在并已启动。(Microsoft SQL Server,错误:25728)

我展开 system_health 并看到目标 package0.event_file 和 package0.ring_buffer。如果我右键单击任一目标并选择“查看目标数据”,则会出现此错误:

使用提供的参数初始化存储失败。(Microsoft.SqlServer.XEventStorage) 无法查看函数“fn_MSXe_read_event_stream”,因为它不存在或您没有权限。(Microsoft SQL Server,错误:15151)

该功能确实存在。我可以运行它:

select * from fn_MSXe_read_event_stream('system_health', 0);
Run Code Online (Sandbox Code Playgroud)

当我这样做时,我收到此错误:

Msg 25728, Level 16, State 10, Line 6
The Extended Events session named "system_health" could not be found. Make  sure the session exists and is started.
Run Code Online (Sandbox Code Playgroud)

我知道 system_health 会话在那里。我在会议列表中看到:

select * from sys.dm_xe_sessions

address name       name
------------------ ------------- 
0x00000001FF6510C1 system_health
Run Code Online (Sandbox Code Playgroud)

我已经用我自己的自定义事件会话尝试过这个。我也看不到他们的实时数据。

我可以从sys.dm_xe_session_targets. …

sql-server extended-events sql-server-2014

9
推荐指数
1
解决办法
3698
查看次数

加入 NULL 键列优化为表和索引扫描

我有一个关于这个查询计划的问题。

我们在测试环境中有一个表 Order_Details_Taxes,它有 11,225,799 行。该表有一个列 OrdTax_PLTax_LoadDtl_Key,它在每一行上都是 NULL。此测试环境的配置方式使此列始终为 NULL。此列上有一个索引。

我使用列的 NULL 值对该表运行了一些查询。NULL INNER JOIN 永远不会产生任何结果。

declare @Keys table (KeyValue decimal(15,0))
insert into @Keys (KeyValue) values (null)

select OrdTax_PLTax_LoadDtl_Key
from @Keys
inner join Order_Details_Taxes
    on OrdTax_PLTax_LoadDtl_Key = KeyValue

select *
from @Keys
inner join Order_Details_Taxes
    on OrdTax_PLTax_LoadDtl_Key = KeyValue
Run Code Online (Sandbox Code Playgroud)

这些是查询计划中的第一个查询。第一个select从亿行表开始并连接到@Keys。第二个select从@Keys 开始,但它对这个表进行聚集索引扫描。

我知道在大多数情况下临时@Tables 是有问题的,所以我将查询更改为使用临时 #Table:

if object_id ('tempdb..#Keys') is not null
    drop table #Keys
create table #Keys (KeyValue decimal(15,0))
insert into #Keys (KeyValue) values (null)

select OrdTax_PLTax_LoadDtl_Key …
Run Code Online (Sandbox Code Playgroud)

null join sql-server execution-plan sql-server-2014

6
推荐指数
1
解决办法
474
查看次数

从更新到意图独占的PAGELOCK转换死锁

我们的一位客户经常遇到僵局。死锁大多在同一个UPDATE语句上。死锁遵循一种模式,其中两个 SPID 都已获取页上的更新 (U) 锁,并且都尝试将 U 页锁向上转换为意图排他 (IX) 锁。有时只涉及一页;有时几个。

我们使用跟踪标志 1222捕获了死锁跟踪。SQL Server 日志显示了许多具有以下模式的死锁(按自下而上的顺序):

waiter id=processe0dc2088 mode=U requestType=convert
waiter id=process2f9db2478 mode=U requestType=convert
waiter-list
owner id=processe0dc2088 mode=IX
owner id=process2f9db2478 mode=IX
owner-list
pagelock fileid=1 pageid=5794 dbid=2 objectname=tempdb.dbo.Item_Package_Site_Costs_Work id=lock1b22de480 mode=IX associatedObjectId=72057594131775488
resource-list
Run Code Online (Sandbox Code Playgroud)

两个进程都运行相同的 UPDATE 语句来在这个 tempdb 表上设置一个标志。此 tempdb 表包含需要在客户端调用之间保留的信息,直到客户端完成。该表有一个相当长的索引,以代表唯一进程 ID 的 GUID 开头。

我很难理解和模拟这种僵局。我用模拟数据尝试了各种数量的记录。

我的问题:

为什么这些进程获取U锁然后转换为IX? 我希望 DELETE 开始获取 IX 锁。

我怎样才能防止死锁?

导致死锁的语句如下。该流程刚刚完成了对单个商店中商品清单的成本查询。它试图指出发现了一个成本。

请注意,UPDATE 语句中有一个已弃用的 (NOLOCK)。这会是一个促成因素吗?

UPDATE tempdb..Item_Package_Site_Costs_Work
SET ItemPkgSiteCost_VINCostFound = 1,
    ItemPkgSiteCost_VendCost_Key = SiteCosts_VendCost_Key
FROM …
Run Code Online (Sandbox Code Playgroud)

sql-server-2005 sql-server deadlock

5
推荐指数
1
解决办法
6130
查看次数

来自不同用户的 sys.databases 的不同结果

我们有一个配置为以用户“dbo”身份运行的 SQL 代理作业。此作业获取sys.databases中定义的与命名方案匹配的数据库列表。然后该作业执行一些动态 SQL 来清理一些旧的事务表。作业从 tempdb 开始。

代理作业在我自己的开发数据库(SQL Server 2008 R2 标准版 10.50.2500.0)上运行良好。作业正确获取数据库列表。但是,在客户系统(SQL Server 2008 R2 标准版 64 位 10.50.1600.1)上,尽管存在匹配的数据库,但作业找不到任何匹配的数据库。

在客户系统上,select * from sys.databases在查询窗口中针对 tempdb的简单运行将返回系统中的所有 10 个数据库。

使用探查器,我EXECUTE AS USER = N'dbo' WITH NO REVERT在运行此作业时看到 SQL 代理调用。我使用以下 SQL 复制了该问题:

use tempdb

-- results: tempdb, <my SQL user>, dbo
select
    db_name() as [Current Database],
    suser_name() as [Current Context],
    user_name() as [Current User]

-- results: tempdb, 10 (which I expect)
select
    db_name() as [Current Database],
    count(*) …
Run Code Online (Sandbox Code Playgroud)

security sql-server system-tables

4
推荐指数
1
解决办法
1967
查看次数

同步查询从 DMV 检索会话和锁

我有一个 SQL 脚本,当我想查看数据库中发生的事情时运行该脚本。该脚本有许多从 DMV 返回信息的查询,但我最常用的两个是“请求”(sys.dm_exec_requestssys.dm_exec_sessions等)和“锁”(sys.dm_tran_locks)。输出类似于 SQL Server 活动监视器,但它显示更多信息。

有时,请求会出现在 Requests 查询中,但它会在 Locks 查询运行之前完成。例如,Requests 查询可能显示 SPID 51 正在等待锁定资源,但 Locks 查询不包含 SPID 51 的任何锁定信息。(我知道来自的wait_typewait_resourcesys.dm_exec_requests。)

有没有办法确保这两个单独的查询显示数据库活动的连贯快照?

我预计商业数据库监控应用程序一定会遇到同样的问题。

我已经尝试在 SERIALIZABLE 并发中运行这些查询并向 DMV 连接添加锁定提示,但查询未获取锁定。无论如何,我不想在生产中这样做。

到目前为止,我最好的想法是:

  1. 从不同的会话同时运行这些查询。

  2. 在一个查询中加入请求和锁。考虑到我一次看到超过 100,000 个锁,这个连接会返回很多重复的请求和会话数据,但它可能会起作用。

我对扩展事件不够熟悉,不知道它们是否会更好地工作——也许是事件配对?

sql-server t-sql dmv

2
推荐指数
1
解决办法
103
查看次数

为什么时间戳并不总是随着并发插入而增加?

我看到时间戳(rowversion) 列出现了一些意外行为。我创建了一个测试表:

create table Test
(
    Test_Key int identity(1,1) primary key clustered,
    Test_Value int,
    Test_Thread int,
    ts timestamp
)

create nonclustered index IX_Test_Value on Test (Test_Value) -- probably irrelevant
Run Code Online (Sandbox Code Playgroud)

我启动了两个线程同时运行插入到这个表中。第一个线程正在运行以下代码:

declare @i int = 0
while @i < 100
begin
    insert into Test (Test_Value, Test_Thread) select n, 1 from dbo.fn_GenerateNumbers(10000)
    set @i = @i + 1
end
Run Code Online (Sandbox Code Playgroud)

第二个线程正在运行相同的代码,只是它正在select n, 2从函数中插入其线程 ID。

先说一下函数。这使用了一系列带有 ROW_NUMBER() 的交叉连接的公共表表达式来非常快速地按顺序返回大量数字。我从Itzik Ben-Gan的一篇文章中学到了这个技巧,所以要归功于他。我认为函数的实现并不重要,但无论如何我都会包含它:

CREATE FUNCTION dbo.fn_GenerateNumbers(@count int)
RETURNS TABLE WITH SCHEMABINDING
AS …
Run Code Online (Sandbox Code Playgroud)

sql-server concurrency sql-server-2008-r2 timestamp

2
推荐指数
1
解决办法
5160
查看次数