LATCH_EX等待资源METADATA_SEQUENCE_GENERATOR


11

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

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

运行此报告的用户越多,获取速度就越慢。我分析了数据库中的活动。在某一时刻,我看到35个单独的请求在流程的某一时刻全部被阻塞。所有这些SPID LATCH_EX在资源上的类型等待时间约为50 ms 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上。


流程实际上是将数据从#Temporary表复制到永久表,还是在该步骤中发生其他转换逻辑?
乔恩·塞格尔

在等待的步骤中,它正在将单个商店的库存记录复制到永久表中,而无需进行转换。我们可以一直在永久表内部进行操作,但是我认为程序员选择使用#Temporary表作为保存区域,以防止对数据的频繁更新转换为PAGE锁。
Paul Williams

Answers:


4

假设您可以将问题隔离到标识值的生成(尝试删除该列作为测试),我建议这样做:

  1. IDENTITY从最终表的列中删除该属性。
  2. 在每个#Temporary表中生成标识值。
  3. 加载最终表时,将特定商店的数字标识符与步骤2中的标识值组合在一起。

因此,如果您拥有商店ID 3和4,则最终将获得最终的ID值,如下所示:

3000000001
3000000002
3000000003
...
4000000001
4000000002
...

或类似的东西。你明白了。

这将消除序列化IDENTITY生成的需要,同时保留最终结果的唯一性。

或者,根据过程的工作方式,将最终计算出的id值插入#Temporary表中。然后,您可以创建将UNION ALL它们组合在一起的视图,根本不需要复制数据。


感谢您的答复。我同意这是否是问题,使用某些制造的钥匙(或完全没有钥匙)可能会解决。我们已与Microsoft就此问题开了一个案子。如果他们同意这是问题所在,我将在此处发布结果并接受您的回答。
Paul Williams

@Paul:请让我知道;我也很好奇 像您一样,我无法在网络上找到任何有关此锁存器的信息,但是它的身份/序列序列化当然是合理的。很难说这是否是瓶颈,尽管有30多个线程争夺价值,这似乎是有可能的。您也可以尝试从每个#Temporary表中进行复制(而不是并行进行),以查看是否有帮助。
乔恩·塞格尔

2
SQL Server工程师同意这可能是IDENTITY专栏文章。我们从已经很宽的聚集索引中删除了它,并完全删除了该列。没必要。之后,这些LATCH_EX等待消失了。我们无法复制对SQL 2008 R2的等待。这个问题只发生在SQL Server 2012中
保罗·威廉斯

@Paul:感谢您的跟进。很有意思。我猜想生成IDENTITY值的代码已被重写,以使用2012年新增的新序列生成东西。在<2012年,您可能会看到不同的闩锁类型,尽管如果没有性能问题,那么似乎有代码中的回归。无论如何,卸下IDENTITY色谱柱是最安全的。
乔恩·塞格尔

除了身份之外,您可以尝试使用“ SEQUENCE”(SQL 2012中的新增功能)
Bogdan Maxim

7

(2019年2月更新)

这是一个古老的帖子,说我终于设法说服了微软,这种事实确实是一个缺陷。

更新: MS确认了缺陷并为其分配了错误号12628722。

我在过去的2018年11月看到了这篇文章,当时我们从Sql Server 2005升级到Sql Server 2017后开始遭受几乎相同的事情。一个曾经耗时10秒进行批量插入的330万行表突然开始耗时10分钟与Identity列的表上。

事实证明,这背后有两个问题:

  1. Microsoft更改了Sql Server 2014中的行为,以强制大容量插入并行运行-在早期版本中,大容量插入被赋予了序列化计划。
  2. 一旦在我们的32核心盒上并行运行,引擎要花更多的时间使核心相互锁定,而不是实际工作。

花了我四个星期,但假期刚过,我从圣诞老人那里收到了一份迟来的礼物-确认问题确实存在。

在解决此问题之前,我们发现了一些可能的解决方法:

  1. Option (MaxDop 1)在查询中使用,可以将批量插入内容转换回序列化计划。
  2. 通过投射来隐藏身份列(例如Select Cast(MyIdentityColumn As Integer) As MyIdentityColumn
    • 这可以防止在使用时复制身份属性 SELECT...INTO
  3. 如上所述,删除标识列。
  4. 将数据库兼容模式更改为Sql Server 2012或更低版本,以重新建立序列化计划。

更新: MS将实施的修复将是将这些插入类型恢复为使用 Serialized 计划。这是针对Sql Server 2017 CU14计划的(其他版本的Sql Server没有消息-对不起!)。实施后,将需要在服务器级别或通过打开跟踪标志9492 DBCC TraceOn

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.