运行在vba中编译并在sql Server中运行的t-sql save或update语句时的查询超时

运行在vba中编译并在sql Server中运行的t-sql save或update语句时的查询超时,sql,sql-server,vba,ms-access,query-timeout,Sql,Sql Server,Vba,Ms Access,Query Timeout,我的公司目前正在运行SQL Server 2000,并且即将跳转到SQL Server 2012,但在升级之前,我们希望尝试解决最近出现的一个性能问题,该问题正困扰着我们的业务能力 几个月前,我们决定在一个sql server表中添加一个文本字段,以尝试捕获特定事件。我想我会在白天尝试添加列,回想起来这可能是第一个错误,但我想如果人们使用该表,SQL Server将不允许我添加列。在这次尝试中,额外的列被接受并添加到表中。然后,我对我们的访问前端进行编码,以写入这个新专栏 不久之后,用户开始体验

我的公司目前正在运行SQL Server 2000,并且即将跳转到SQL Server 2012,但在升级之前,我们希望尝试解决最近出现的一个性能问题,该问题正困扰着我们的业务能力

几个月前,我们决定在一个sql server表中添加一个文本字段,以尝试捕获特定事件。我想我会在白天尝试添加列,回想起来这可能是第一个错误,但我想如果人们使用该表,SQL Server将不允许我添加列。在这次尝试中,额外的列被接受并添加到表中。然后,我对我们的访问前端进行编码,以写入这个新专栏

不久之后,用户开始体验Access GUI“锁定”,并最终抛出查询超时错误

下面是错误发生的方式。单击Access前端中的“保存”按钮(该按钮随后将在VBA中生成T-SQL语句以更新或保存新记录)后,用户将不会看到显示保存成功或发生错误的Access消息框。相反,他们会得到一个访问系统对话框,上面说有一个查询超时。此时,我删除了我添加的专栏,希望能解决这个问题

我首先让每个人关闭他们的访问程序,然后让遇到问题的人重新打开并再次尝试保存。这对该用户有效,我将允许其他所有人此时返回系统。当然,当时我不确定为什么这样做有效,所以我试着更多地研究这个问题。进一步的分析使我找到了sp_who2。运行它会给我所有的用户和阻塞者的SPID。这给了我一个更快的方法让事情重新运转起来,因为我可以杀死冒犯的SPID,让其他人继续工作。当然,kill会导致回滚,因此并非所有数据都被保存,我必须告诉kill进程的所有者,他们必须再次重新输入所有数据。到目前为止,我一直以这种方式监视这个数据库,如果我发现有什么东西被阻塞,这就是我修复它的方法

我知道这个数据库中只有一个表存在问题,首先是因为问题是在我尝试输入一个新列之后才开始的,而且还因为每次执行保存或更新时,它都会在写入这个特定表时锁定。当时,我诊断这个问题是因为我问我的用户他们试图执行什么操作,在所有情况下,他们都试图对这个特定的表执行一些操作。事实上,对同一数据库中其他表的更改执行时不会出现任何问题。所以我觉得这个问题可能和这个表的腐败有关

我做的第一件事是运行CHECKDB和CHECKTABLE,但它们都没有返回表的问题。所以我们决定重建表。我手工重建了表,然后将数据从原始表复制到新表。我相信我为此使用了sql工具,但我可能已经在中运行了一个insert。(已经有一段时间了,我没有记录。)不管怎样,它都不起作用。该组织继续遭受封锁。然后我重新索引了这个表,这似乎起了作用,持续了大约一天,然后错误“回来了”。从那时起,我找到了INPUTBUFFER,我在阻塞用户的SPID上运行了一段时间。几乎每一次,INPUTBUFFER都会返回一个SELECT语句,尽管我不认为这是抛出块的原因。我不认为SELECT抛出了阻塞,因为在accessgui中,您点击save按钮,它运行save或update,然后运行SELECT刷新Access屏幕。我认为,如果SELECT抛出了块,那么保存就会发生,但是当在进程开始阻塞并且进程被终止后调用记录时,用户所做的更改永远不会保存到记录中。我不完全确定INPUTBUFFER是如何工作的。我知道它可能会返回发送到SQL Server的最后一条语句,但如果保存没有提交,Access还会将SQL发送到SQL Server吗

我还要补充一点,当我在SQLServerManagementStudio中工作时,我似乎从来没有遇到过阻碍。显然,我已经感受到了现有块的影响,它将挂起我的sql语句,但据我所知,我从未抛出过一个块。为此,我还将ODBC连接器从每个用户更新为10.0。这似乎对这个问题没有消极或积极的影响


所以我不知道下一步该怎么办。如果您有任何建议,我们将不胜感激。

在使用链接表时,请确保您的SQL Server表具有唯一标识符

查看我关于如何链接表的文章

第二个问题是你得到的是什么类型的锁

下面是我不时做的一个演示中的一些代码。将adventureWorks2012更改为您的数据库名称

这应该会显示发生了什么锁。选择正确的hobt\u id或object\u id以了解详细信息

--
-- Locked object details
-- 

-- Old school technique
EXEC sp_lock
GO

-- Lock details
SELECT
    resource_type, resource_associated_entity_id,
    request_status, request_mode,request_session_id,
    resource_description 
FROM sys.dm_tran_locks
WHERE resource_database_id = DB_ID('AdventureWorks2012')
GO

-- Page/Key details
SELECT object_name(object_id) as object_nm, *
FROM sys.partitions
WHERE hobt_id = 72057594047037440
GO

-- Object details
SELECT object_name(1266103551)
GO
阻止是SQL server允许会话之间协同执行的一部分。问题是当它变成死锁或SQL server没有检测到死锁时

一些解决方案是改变隔离级别。但这也有其自身的问题——幻象读取、脏读取、不可重复读取和低并发性。首先要查看的是锁序列。请贴一张图片

由于您使用的是SQL Server 2000,请查看sp_索引选项

概述:

例如,当一个表被认为是争用点时,不允许页级锁是有益的,因此只允许行级锁。或者,如果总是使用表扫描来访问索引或表,则不允许页级锁和行级锁可以帮助
USE Northwind
GO

EXEC sp_indexoption 'Customers.City', 
   'disallowpagelocks', 
   TRUE
GO