持续扫描需要 0 秒或 2-3 分钟

Eve*_*zon 10 sql-server

像下面这样的查询保证不返回任何行,在我们的一台服务器上需要 0 到 160 秒的任何时间:

select col1, col2, col3
from tab1
where 0 = 1
Run Code Online (Sandbox Code Playgroud)

两周前,这种情况在 48 小时内发生了六次。上周相同的查询花费了大约 0 秒。我有我们应用程序 SQL 的日志,但还没有发现任何嫌疑人。此外,我认为 top 0/where 0=1 类型查询永远不会命中数据页,所以它应该可以抵抗行/页/表级数据锁?任何(已知的)SQL 都不会触及该架构。

由于问题不一致,并且服务器负载非常重,我想在附加 SQL 探查器之前了解所发生情况背后的理论。在这些延迟期间,其他查询运行没有问题。应用程序中的一个已知问题是大量动态创建的 SQL 查询 - 在 48 小时内总共有 850k(记录)查询的大约 200k 唯一查询,这会导致这样的问题吗?

该服务器运行 SQL Server 2005 标准版、96 GB RAM、SAN 磁盘和 4 个 CPU/16 核。数据库文件和文件组得到了很好的优化,应该不会有问题(但我们正在单独研究这一点)。

非常感谢任何可以查看的指针。

编辑:完美!重播查询以添加执行计划,耗时 1 分 35 秒。这是显示查询持续时间的执行计划和屏幕截图: 查询计划

编辑 2:统计第二次运行的时间详细信息。现在似乎一直很慢,所以我们将附加分析器和性能:

SQL Server Execution Times:
   CPU time = 0 ms,  elapsed time = 97402 ms.
SQL Server parse and compile time: 
   CPU time = 0 ms, elapsed time = 0 ms.
Run Code Online (Sandbox Code Playgroud)

Tho*_*ger 18

似乎即使有一个... WHERE 0 = 1子句,仍然需要对表的意图共享 ( IS) 锁。让我们证明这一点:

我将从创建一个测试表开始:

use TestDb1;
go

create table dbo.MyTestTable1
(
    Id int identity(1, 1) not null,
    SomeInt int not null
);
go

insert into dbo.MyTestTable1 (SomeInt)
values (10), (20), (30), (40), (50);
go
Run Code Online (Sandbox Code Playgroud)

现在我有了我的测试表,在一个会话(查询窗口)中,我将执行以下操作来放置一个独占 ( X) 锁dbo.MyTestTable1

use TestDb1;
go

begin tran;
    select
        Id, SomeInt
    from dbo.MyTestTable1 with (tablockx);
--commit tran;
Run Code Online (Sandbox Code Playgroud)

我可以通过查看sys.dm_tran_locksDMV来验证排他锁。然后在另一个会话(新查询窗口)中,我完全按照您的查询进行操作:

use TestDb1;
go

select
    Id, SomeInt
from dbo.MyTestTable1
where 0 = 1;
Run Code Online (Sandbox Code Playgroud)

乍一看,我看到它没有完成。看着sys.dm_exec_requests,我明白为什么会这样:

select
    r.session_id,
    r.status,
    r.wait_type,
    r.wait_time,
    r.wait_resource,
    r.blocking_session_id
from sys.dm_exec_requests r
cross apply sys.dm_exec_sql_text(r.sql_handle) st
where st.text like '%where 0 = 1%'
and r.session_id <> @@spid;
Run Code Online (Sandbox Code Playgroud)

在此处输入图片说明

我可以在这里看到我的... WHERE 0 = 1查询正在等待IS此对象的锁定(object_id 转换为dbo.MyTestTable1)。

我绝不是说并发是你的问题,但从它的声音来看,你正在表现出症状。上面的示例是为了证明即使使用WHERE永远不会返回数据的子句,您也不能免于锁定和阻塞。

我们所能做的就是猜测,所以当它“需要很长时间”时,您需要做的是确切地查看该请求正在执行的操作需要很长时间。如果它在等待什么,那么看看它在等待什么。