并发使用表导致问题

时间:2010-04-08 08:30:23

标签: sql-server

在我们目前的项目中,我们正在与第三方数据提供商进行接口。 他们需要在我们的表格中插入数据。这种插入可以每1分钟频繁,每5分钟,每30分钟,取决于他们需要提供的新数据量。使用隔离级别读取已提交。在我们的最后,我们有一个应用程序,Windows服务,每2分钟调用一次Web服务,以查看此表中是否有新数据。我们的隔离级别是可重复读取的。我们检索记录并更新这些行的列。

现在的问题是,有时这个第三方提供商需要插入大量数据,比方说5000条记录。它们按事务执行此操作(每个事务5个),但它们不会关闭连接。他们做一个交易然后下一个直到插入所有记录。这导致了我们的流程问题,我们收到了超时。

如果这种情况持续很长时间,数据库就会完全不稳定。例如,他们可能会停止,但桌子仍然保持不可用。当我尝试在桌子上做一个选择时,我得到了几个记录,但在某个时刻我不再得到任何回应。它只是说检索数据但在我收到超时异常之前什么都没有。

唯一的解决方案是重新启动数据库,然后我会看到其他记录。

我们如何解决这个问题。在这种情况下,理想的隔离级别设置是什么?

2 个答案:

答案 0 :(得分:1)

您考虑过Snapshot isolation了吗?从体系结构的角度来看,如果您为第三方创建集成机制并自己处理插件会更好 - 也许让他们通过消息队列向您发送更新?

答案 1 :(得分:1)

也许您可以创建第三方数据提供者可以写入的临时表。然后,您可以编写自己的例程,将数据从那里拉入实际表格,使用您选择的方法更好地适用于您的应用程序。

编辑基于OP的评论

你问的问题

  

现在的问题是,有时这个   第三方提供商需要插入一个   很多数据,比方说5000条记录。   他们每次交易都这样做(5个   每笔交易),但他们没有关闭   连接。他们做了一个   交易,然后下一个直到   插入所有记录。这造成了   我们的流程问题,我们收到了   超时。

这表明您已将问题确定为第三方数据提供者如何插入数据,并暗示您无法更改数据。我建议将它们插入到临时表中,以释放您的应用程序,以防止由第三方数据提供程序引起的任何锁定和/或阻塞。然后,您可以使用任何隔离级别,每次任意数量的行,任何时间或特定时间等将数据包含到您的应用程序中。

但是,我很困惑如何在表中插入新行会导致应用程序锁定。如果它是锁定/阻塞,为什么你的应用程序在插入它们时会读取这些新行?您是否使用聚集索引插入表格中间的行?您的应用程序是否在事务中进行表扫描选择?必须有其他事情发生。

当你的系统开始死时试试这个,它会告诉你导致阻塞的原因是什么:

;with Blockers AS
(SELECT
     r.session_id AS spid
         ,r.cpu_time,r.reads,r.writes,r.logical_reads 
         ,r.blocking_session_id AS BlockingSPID
         ,LEFT(OBJECT_NAME(st.objectid, st.dbid),50) AS ShortObjectName
         ,LEFT(DB_NAME(r.database_id),50) AS DatabaseName
         ,s.program_name
         ,s.login_name
         ,OBJECT_NAME(st.objectid, st.dbid) AS ObjectName
         ,SUBSTRING(st.text, (r.statement_start_offset/2)+1,( (CASE r.statement_end_offset
                                                                   WHEN -1 THEN DATALENGTH(st.text)
                                                                   ELSE r.statement_end_offset
                                                               END - r.statement_start_offset
                                                              )/2
                                                            ) + 1
                   ) AS SQLText
     FROM sys.dm_exec_requests                          r
         JOIN sys.dm_exec_sessions                      s ON r.session_id = s.session_id
         CROSS APPLY sys.dm_exec_sql_text (sql_handle) st
     --WHERE r.session_id > 50
)
SELECT Blockers.* FROM Blockers