【问题标题】:Delete multiple rows from table with frequent reads and writes从频繁读写的表中删除多行
【发布时间】:2015-09-23 15:22:17
【问题描述】:

我有一个经常读取、插入和更新的表(它保存网站用户的会话数据)。它在名为sessionIDvarchar 字段上有一个聚集索引。

我需要根据另一个表中的sessionIDs 列表删除一堆记录。当我尝试一次删除大量它们时,会创建一个锁,以防止表被写入和读取。

如果我在 SSIS 包中使用 foreach 循环逐行删除它们,似乎消除了锁定。

逐行删除是否有任何可能的长期负面影响?

【问题讨论】:

  • 用你说的方法有效,是不是锁反了?如果是这样,您可能会从读取尚未提交的数据中获取脏数据。这当然取决于您如何删除数据。
  • 不确定,但这可能会让您的日志文件增长得非常快。我认为您不需要逐行删除,最好弄清楚锁不会伤害其他活动的块大小和delete in chunks
  • 感谢@DrCopyPaste,这是一个有用的链接。我确实运行了一个测试以逐行删除 5000 条记录,并且事务日志根本没有增加。 (简单恢复模型)我们目前一次删除 5000 个块,这正在创建锁。
  • 对于这种情况可以考虑使用逻辑删除
  • 您也可以在较小的主干中删除,例如一次删除 250 行中的 100 行。大多数情况下会越来越快,而且桌子会被锁定得更短

标签: sql sql-server tsql ssis


【解决方案1】:

好的,这是一个关于选项卡锁、页锁和行锁的问题。发生的事情是您要从多个页面中删除,因此 sql 会锁定整个表。 Sql 通常对每个事务使用一个锁,因此它会选择覆盖所有受影响行的最小锁。删除单行会使用行锁,删除多条连续记录会使用页锁,从多个页删除记录会锁定整个表。

使用 varchar 作为 PK 和聚集索引,您不太可能遇到页面锁定,因为记录在表中出现的顺序是随机的(稍后会详细说明为什么这是非常不受欢迎的)。所以你的选择是行锁或制表锁,因为锁定表不是一个选项,行锁是你唯一的选择。

至于不良影响,drcopypaste 提到了事务日志问题,但如果您的 PK/集群不是连续的,则会出现更糟糕的问题。如果每次插入记录或删除记录时都不是连续的,则数据库必须移动所有后续记录,因为聚集索引(几乎总是在表 pk 上)是行在表上的物理排序方式.

【讨论】:

  • 谢谢,所以听起来逐行是唯一的选择,但理想情况下,我们希望创建一个不同的表,该表具有一个身份作为主键,然后是 sessionID 上的索引?
  • 取决于您的 PK(varchar)是否是连续的,如果是,那么它不是什么大不了的事(它使索引变大并减慢任何读取速度但还不错),如果不是然后您可以向表中添加一个标识列,将 clustered 和 pk 切换到该列,并将更改该表所需的磁盘 IO 减少一个数量级或更多。
猜你喜欢
  • 1970-01-01
  • 2013-08-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-10-02
相关资源
最近更新 更多