【问题标题】:Solving Deadlock Issues解决死锁问题
【发布时间】:2016-04-20 14:40:06
【问题描述】:

在数据库 A 表中频繁发生 SELECT、UPDATE、BULK INSERTS 并且发生严重阻塞,并且每次 BULK INSERT 被选为死锁牺牲品时,我们都会因为 BULK INSERT 失败而丢失一些数据。

SELECT 阻止 BULK INSERT 或 UPDATE 每次都阻止 BULK INSERT,反之亦然,所有这些语句(查询)都来自应用程序。我们没有使用任何存储过程(不幸的是我们不能使用存储过程)

数据库快照是 READ Committed,简单的恢复模型,正确索引并且没有发现碎片。统计数据是最新的,正确设置了 MAXDOP,针对临时工作负载进行优化 = 1,AUTO_UPDATE_STATISTICS_ASYNC ON,mdf 和 ldf 的自动增长为 500mb,mdf 和 ldf 的 tempdb 自动增长为 500mb ..btw,所有数据库都在同一个磁盘。内存为 6GB。数据库总大小(如果为 60GB)。 SQL Server 2012 标准版。 PageFile.Sys 为 9.8GB。等待统计是 LCK_M_IX(59%),PAGEIOLATCH_SH(25%)

我想知道,有没有办法解决这个问题?

  1. 有没有办法强制来自应用程序(查询计划)的代码在 SELECT 上使用 NO LOCK?或以任何方式强制任何查询或任何登录 xyz 应用程序使用 NO LOCK?

  2. 将 ISOLATION LEVEL 更改为 READ UNCOMMITTED 有帮助吗?

  3. 将死锁优先级设​​置为 LOW?

【问题讨论】:

  • 这对SO来说是一个很大的话题,但是你有没有仔细研究过,为什么会死锁?选择是读取表的大部分还是整个表被锁定?
  • ...你在期待什么? BULK INSERT 旨在单独运行,或与其他 BULK INSERT 语句同时运行。它绝对不会与同一张桌子上的其他语句配合得很好。你可以在临时表中 BULK INSERT 代替,然后从那里做一个常规的 INSERT 吗?
  • 您能否将您的一些工作负载更改为更小的批次?我确信有更优雅的解决方案,但这可以提供一些暂时的缓解,这意味着您不必重新启动整个批量插入。
  • JamesZ:选择读取表格的大部分 -- 是
  • Jeroen:你能不能在临时表中批量插入,然后从那里进行常规插入——所有代码都是从应用程序调用的,我无法控制。

标签: sql sql-server


【解决方案1】:

BULK INSERT 命令有一个表锁定选项,它可能对您的情况有所帮助。如果您的批量插入可以在您要插入的表上获得排他锁,则其他进程将被阻止使用该表,直到批量插入完成。这应该允许您的批量插入避免死锁;但是,如果您的批量插入长时间运行,预计其他竞争进程会被阻止并可能超时。

请参阅下面来自 MSDN https://msdn.microsoft.com/en-us/library/ms188365.aspx 的摘录。

选项卡

指定在大容量导入操作期间获取表级锁。如果表没有索引并且指定了 TABLOCK,则可以由多个客户端同时加载表。默认情况下,锁定行为由表选项table lock on bulk load决定。在大容量导入操作期间持有锁可减少表上的锁争用,在某些情况下可以显着提高性能。有关性能注意事项的信息,请参阅本主题后面的“备注”。

【讨论】: