为啥“SELECT 1 from <table>”会导致另一个进程上的 LCK_M_IX 执行 DELETE

Posted

技术标签:

【中文标题】为啥“SELECT 1 from <table>”会导致另一个进程上的 LCK_M_IX 执行 DELETE【英文标题】:why does "SELECT 1 from <table>" cause a LCK_M_IX on another process doing a DELETE为什么“SELECT 1 from <table>”会导致另一个进程上的 LCK_M_IX 执行 DELETE 【发布时间】:2013-04-02 00:56:19 【问题描述】:

我有一张表列出了 patient_clinic_visits。我有 SQLSERVER 2005 后端。 Access2010 前端。

每天早上都需要从医院大型机的数据转储中刷新此表。

此数据转储包括前一天的信息(谁参加、没有参加、取消)和未来 6 周的预约。

因此,我执行“DELETE * from Patient_clinic_visits where Visit_Date > (a day) and

在大多数情况下,每天只有大约 100-150 条记录。它们是 Master_Patient_Table 中 Pat_ID 的一个外键,上面有 NO_ACTION 链。

目前,在处理了几天的数据后,此 Delete 查询在 Access 前端中超时(即在星期一、星期二、星期三......)

我运行 sp_whoisactive 并得到:

00 01:53:01.926 52 [[query SELECT 1 FROM "dbo"."Patient_Clinic_Visits" ]] RAHCC_User (265ms)ASYNC_NETWORK_IO 0 0 0 NULL 51 0 0 2 暂停 0 NULL SAH0020663 RAHCC_DB Microsoft MDB RAHCC 2013-04- 02 09:08:33.027 0 2013-04-02 11:01:35.033

00 00:00:27.610 53 [[查询 -- 删除 Patient_Clinic_Visits WHERE Clinic_date >= '26-Mar-2013' AND Clinic_date

这表明我的客户端前端正在等待“来自 Patient_Clinic_Vists 的 SELECT 1”,这会阻塞该过程。显然这是由于客户端上的 ASYNC_NETWORK_IO 造成的(这可能发生在 Access 前端执行表请求然后不处理数据时)。

a) 但是,“从 Patient_Clinic_Visits 中选择 1”实际上应该只返回 TRUE 或 FALSE ?这不太可能填满任何东西,并且不清楚为什么会导致阻塞情况?

b) 我在任何地方的 Access 前端都找不到“SELECT 1...”。这可能是 SQLSERVER 为响应更复杂的选择而做出的一系列子选择的一部分吗?如果是这样,我如何在该进程历史记录中找到导致这种情况的真正选择?

干杯,

JonHD

【问题讨论】:

【参考方案1】:

a) 查询“从 Patient_Clinic_Visits 中选择 1”将返回一个空结果集(如果 Patient_Clinic_Visits 表为空)或一个包含与 Patient_Clinic_Visits 表一样多的行的结果集,每行都有一个 1。为此,SQL Server 必须针对整个 Patient_Clinic_Visits 表发出查询,这(假设默认锁定行为)将导致共享(读取)锁成为针对该表中的行的问题。

b) (注意:OP 在 cmets 中解决了这一点)我可能遗漏了一些东西,但我看不出您在哪里提出了基于 sp_whosactive 的“从 Patient_Clinic_Vists 中选择 1”查询。了解从应用程序发送到数据库服务器的 SQL 的最佳方式可能是使用带有适当过滤器的 SQL Profiler(可能仅过滤来自运行应用程序的主机的连接)。

【讨论】:

谢谢你解释得很好。我很抱歉,但是 sp_whosactive 没有被 *** 正确格式化,并且查询被复制为 XML 字符串并被编辑掉 - 我已经修复了它。我正在运行 SQLSERVER2005 Express。我不相信这个版本提供了 Sql Profiler。 我发现“选择 1...”的来源是以下 SQL,用于将“(全部)”选项拼接到组合框结果中。这是罪魁祸首 SQL:>>

以上是关于为啥“SELECT 1 from <table>”会导致另一个进程上的 LCK_M_IX 执行 DELETE的主要内容,如果未能解决你的问题,请参考以下文章

为啥 DataGridView 上的 DoubleBuffered 属性默认为 false,为啥它受到保护?

为啥需要softmax函数?为啥不简单归一化?

为啥 g++ 需要 libstdc++.a?为啥不是默认值?

为啥或为啥不在 C++ 中使用 memset? [关闭]

为啥临时变量需要更改数组元素以及为啥需要在最后取消设置?

为啥 CAP 定理中的 RDBMS 分区不能容忍,为啥它可用?