【问题标题】:How to force after insert trigger to execute just after its insert, before any other insert is executed?如何在插入触发器之后强制在其插入之后执行,然后再执行任何其他插入?
【发布时间】:2012-06-30 02:01:45
【问题描述】:

这个问题是关于并发高速插入的。 我必须承认这在我眼中很有趣。

我正在使用 SQL Server 2008 R2 执行 T-SQL 插入和插入触发器之后。

我想确保在插入和插入后触发器之间不会执行任何命令。

使用隔离级别会导致死锁,或者只是不能解决问题。

我正在使用的程序是 Phil 的答案/解决方案 SQL Server dependent Identity - is there such a thing?

问题是:

有时插入会在前一个插入与其后插入触发器之间插入,从而导致以下结果:

RoomID  ItemID  ItemDescription ID
------  ------  --------------- --
7       1       Door             1
7       2       Window (West)    2
7       3       Window (North)   3
8       1       Door             4
8       2       Table #1         5
8       3       Table #2         6
7       4       Table #1         7
8       4       Chair #1         8
7       6       Table #2         9
7       5       Table #3        10
8       5       Chair #2        11

参见 ID #9 和 #10。 Thair ItemID 已切换。 ItemID 应该分别是 5 和 6 而不是 6 和 5,但第 10 次插入可能发生在 #9 的后插入触发器完成执行之前。

在少于 0.5% 的插入中发生此问题:2 次切换涉及 4 条记录,插入次数为 1000 次或更少。是的,有时没有开关发生。

一步提高隔离级别无济于事,甚至会导致更多的keys/dependent-keys不时切换。提高两个隔离级别会导致死锁。

降低隔离级别会减少开关,但仍会创建它们。

在每次插入之前开始提高隔离级别并在触发器结束时移回默认隔离级别会导致死锁(在我的实验中,所有插入都没有提交!)。

有人找到出路吗?

如何强制一个insert和它的after insert触发器一起执行,禁止其他insert到同一张表之间?

【问题讨论】:

  • 我不清楚 ItemID 是什么或做什么。您可以使用计算列而不是 after 触发器来查找它吗?
  • 另外,在 SQL 2012 中,您可以使用序列。
  • 你能告诉我们...1插入前的表格。 2 插入自己,以及它们的顺序。 3 触发器中的代码。
  • @dems - 可以从空表开始(不是必须的)。许多插入试验几乎同时进行。例如,插入包括 RoomID 和 ItemDescription(这是一个下拉列表 - 没有错误,没有代码,没有重要性,我是 null)(忘记 ItemDescription,像 INSERT Rooms (RoomID) VALUES (1) 这样的插入并不重要,对于示例。触发代码与源解决方案完全相同:update Rooms set ItemID = (select coalesce(MAX(itemid), 0) + 1 from Rooms r where r.RoomID = inserted.RoomID ) from inserted where Rooms.Id = inserted.Id。就是这样。谢谢。
  • @david-manheim - ItemID 是一个依赖身份。它是同一个 RoomID 的插入序列号。由于权利,顺序很重要。我目前受限于 Sql 2008 R2。谢谢。

标签: sql sql-server sql-server-2008 tsql sql-server-2008-r2


【解决方案1】:

使用instead of insert trigger 怎么样?

当然,您必须自己进行实际插入,但这是 SQL Server 中支持的行为。没有 before insert 触发器 或类似的东西。

无论如何,您仍然可以在这种类型的触发器中使用您当前的触发器处理逻辑。

为了尝试想象一个更好的解决方案,您能解释一下您要做什么吗?此表中是否插入了多个线程?这是一个实时过程吗?

就像拍卖一样。是的,该表中插入了多个线程。 问题在后面,但发生了。还没有投诉的理由,但是 可能有(现在发生的开关不是关键的 观点)。发起插入的用户需要知道他们的 订单列表中的优先级。 ItemID 几乎立即使用, 因此,可能无法即时计算(使用 select count(*)... where..) 稍后需要几毫秒的时间。错误的顺序 ItemID 可能会导致一个人的损失和另一个人的非法收益。

嗯,多线程插入在 SQL Server 中几乎从来都不是一个好主意。至少不是没有某种同步。

你需要某种排队。 例如,我有一个类似的系统,每天需要插入 2.5-3 百万条记录(嗯,工作时间)。

起初我还使用 8-16 个线程直接在数据库上进行插入。我注意到了这种行为:死锁。所以我开始考虑如何将这些消息排队,以便随时插入 1 个线程(1 个连接)。

我最终在 MSMQ(事务性)中对这些记录进行了排队。其他一些过程从这里(也是事务性的)来并把它们分批插入到数据库中。我的记录保证以正确的顺序出现,也就是发送它们的顺序。

因此,此辅助过程会插入成批记录,并且像您一样,我需要在插入之前进行一些预处理,我正在使用而不是插入触发器来执行此操作。在那里我可以“安静地”更新整个inserted 表,而不必担心有人会来弄乱我的东西。

这只是一个想法。您可能还需要考虑使用 Service Broker 进行排队,尤其是如果您不想在 SQL Server 之外进行处理。

此外,与Snapshot Isolation level and row versioning 的事务值得一试,但我建议采用 MSMQ/Service Broker 方式。

【讨论】:

  • 就像拍卖一样。是的,该表中插入了多个线程。问题在后面,但发生了。还没有抱怨的理由,但可能有(现在发生的转变不是在关键点)。发起插入的用户需要知道他们在订单列表中的优先级。 ItemID 几乎立即使用,因此,可能不会在稍后需要几毫秒时即时计算(使用 select count(*)... where..)。错误的 ItemID 顺序可能导致一方损失,另一方获得不正当收益。
  • @Different111222 - 请点击此答案提供的链接。使用INSTEAD OF 触发器而不是AFTER 触发器。
  • @Different111222:用替代方法更新了答案(实际上是两个)。
猜你喜欢
  • 2015-10-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-10-09
  • 2016-12-22
  • 2013-01-19
  • 1970-01-01
相关资源
最近更新 更多