【问题标题】:DataInconsistancy in SQL Server 2000 due to Long Running Transaction由于长时间运行的事务,SQL Server 2000 中的数据不一致
【发布时间】:2011-07-30 13:22:28
【问题描述】:

我们的一个生产服务器正面临一种情况。 我们有一个特殊的存储过程,它对数据库中最大的表之一执行插入操作(它有几百万行)。该表是数据库中最繁忙的表,有许多依赖于它的操作。

最近我们在一个特定的生产服务器上遇到了一个问题。

我们在一个事务中执行插入 SP 以及其他一些更新 SP,并且我们经常面临插入 SP 的“长时间运行事务”问题。当我们遇到这个问题时,我们会在插入到表中的数据中发现一个典型的行为。 datetime 列值被插入为“null”。它发生在所有行的某些时间和一些行的某些时间。日期时间值是从应用程序传递的。 但是在插入操作之前和之后执行的其他更新操作运行良好。

我们在测试环境(不在生产​​服务器中)运行了 sql profiler trace,但发现 datetime 值每次都正确传递。

当我们在生产中遇到问题时,我们观察到:

  1. @@trancount 等于“0”,但 DBCC OPENTRAN 显示 特定的公开交易。
  2. Last Wait 类型的值为“NETWORKIO”。
  3. 等待类型为“0x0000”。
  4. 状态为“睡眠”。
  5. 隔离级别已读取未提交。

所以我们关心的是

  1. 为什么仅在这种特殊情况下将日期时间插入为“NULL”?
  2. 如何避免这种情况以及长时间运行的事务?
  3. 在一台特定服务器上出现这种情况的原因可能是什么?

提前感谢您的帮助,

阿比吉特

【问题讨论】:

  • 长时间或短时间运行的事务不会导致这种情况。出现问题是因为您的过程中存在错误,包括您执行脏读的事实。
  • 我同意 Remus 的观点,尤其是在“脏读物”方面。关于为什么它发生在一台特定的服务器上,也许它是最繁忙的?
  • 您能否发布一个经过清理的程序代码示例,以便我们对其进行调试?
  • 我猜您不小心将 datetime 输入变量设置为 NULL,这就是它被插入为 NULL 的原因。这可能是由 Remus 所讨论的脏读相关问题触发的。

标签: sql sql-server-2000


【解决方案1】:

我认为这里需要同时解决一些问题。首先,也是最重要的,我强烈建议您查看该事务,看看您可以做些什么来减少它对您的系统施加的负载。它可以分解成多个较小的交易吗?添加更好的索引会有所帮助吗?捕获数据子集并将其放入临时表会减少针对主表运行的 SELECTS 数量吗?这里的问题列表可能会持续一段时间。

接下来,查看启动事务的“应用程序”。它正在传递日期吗?如果是这样,它是如何做到的?如果它只是传入GetDate(),那么它会让SQL Server 完成这项工作。但是,如果应用程序传入一个日期值,我会确保这个日期值始终有效。如果是,请查看表格以确保正确设置日期格式。例如,如果您的应用程序以14-05-2011 的欧洲日期格式传递,那么如果它期望月-日-年,您的应用程序可能会阻塞,因为 14 不会转换为一个月。

第三,查看您的表格,看看您是否在它们上设置了任何触发器。如果这样做,请仔细查看每个触发器。触发器很可能导致您的事务中发生冲突。也许您正在写入数据并且您的触发器正在返回并更新数据(或者它正在评估日期并说它无效 - 参见上面的示例)。

第四,在数据离开交易之前检查数据。当它进来时阅读它,并在执行INSERT 之后阅读它。事务完成后,可能有客户端操作正在清除日期值。

最后,您需要查看您的测试环境。如果这在测试中有效,但在生产中无效,则两个系统之间存在一些不同。这就是原因,无论是直接的还是间接的。可能是硬件相关(RAM 损坏?),也可能是设置不同(锁定、客户端试图对数据执行操作等)

除此之外,这里还有一个论坛链接,其中包含一些其他可能的答案:

http://groups.google.com/group/comp.databases.ms-sqlserver/browse_thread/thread/1063b65df1f97492/8649bee2002646a2

【讨论】:

  • @Abhijit - 请与我们分享,以便我们都能受益。谢谢。很高兴你让它工作。
  • 我开始知道为什么会发生数据不一致。实际上,用户触发了两次交易。当用户第一次触发交易时,他的客户端屏幕会冻结。所以他会关闭它并再次打开屏幕并重新触发相同的动作。正如 Remus 上面所说的那样有效地发生了一些脏读,这会导致数据不一致(@Remus:感谢您的建议)。因此,这种类型的事务(2 个事务在同一个表和相同的数据上相互并行运行)可能会导致事务长时间运行。
  • 对我来说仍然没有答案的是为什么只有在为一个特定客户(例如客户 A)插入数据时才会发生长期运行的事务。它不会发生在任何其他客户身上。此外,插入的数据量对于所有客户来说几乎是相等的。您可以分享任何想法..
【解决方案2】:

听起来你的代码很乱。建议将您的插入和更新等隔离到较小的事务中。

要测试您的挂断发生在哪里,您可以尝试的一件事是简单地以 print('Made it this far...') 的形式将一些里程碑添加到您的过程中。然后从 SSMS 执行该过程并检查消息窗口。这是一种丑陋的调试方式,但如果您不想使用较小的事务或陷阱@@error 等,它可能是您的最佳选择。

【讨论】:

    【解决方案3】:

    “我们在一个事务中执行插入 SP 以及其他一些更新 SP”

    我建议您将插入和更新分离。如果您知道需要在插入后进行一些更新,那么触发更新可能是正确的答案。

    我还建议您对锁定/阻止进行配置文件。我这样说是因为根据您所说的,您很可能会在根事务中不止一次地跟踪相同的行,这可能是基于将所有这些活动捆绑在同一个过程中的原因。

    【讨论】:

      猜你喜欢
      • 2023-04-05
      • 1970-01-01
      • 2011-04-23
      • 2013-09-28
      • 2018-05-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多