每天我都有一个会话产生 Avg.Disk Queue Length > 800(5 分钟间隔)。
我发现就在这之前 Sql Server 优化器犯了一个错误:它决定使用一个不合适的计划进行聚集索引扫描,这会产生大约 100Mb-1GB 的 IO 操作。假设我找到了排队的原因,但这不是全部。
恕我直言,巨大的 IO 不一定会冻结其他用户 15 分钟。虽然我不知道谁负责创建过多的异步 IO:Sql Server、Windows 文件系统,或者可能是物理 IO 控制器,但是产生的异步 IO 会导致一个巨大的异常队列,并且没有留下任何机会供其他会话从磁盘读取。
有没有办法控制异步IO?我想如果我能够降低队列长度(顺便说一句,“更真实的”当前队列长度计数器显示队列中有 400 个操作),那些查询计划的问题将不会冻结其他会话。
不过情况比较复杂:
更新:该表一点都不有趣,只是它对于 NAV 来说太大了(1 GB 带索引)。
一些查询的示例:
declare @p1 int set @p1=180150129 declare @p3 int set @p3=16 declare @p4 int set @p4=1 declare @p5 int set @p5=0
exec **sp_cursoropen** @p1 output,N'SELECT * FROM "DBNAME"."dbo"."COMPANYNAME$Cust_ Ledger Entry" WITH (READUNCOMMITTED) WHERE
(("Customer No_"=@P1)) AND
(("Open"=@P2)) AND
"Customer No_"=@P3 AND
"Open"=@P4 AND "Positive"=@P5
AND "Due Date"=@P6
AND "Currency Code"=@P7
AND **"Entry No_"<@P8**
ORDER BY "Customer No_" DESC,"Open" DESC,"Positive" DESC,"Due Date" DESC,"Currency Code" DESC,"Entry No_" DESC OPTION (FAST 5)',@p3 output,@p4 output,@p5 output,N'@P1 varchar(20),@P2 tinyint,@P3 varchar(20),@P4 tinyint,@P5 tinyint,@P6 datetime,@P7 varchar(10),@P8 int','PARAMETERVALUE',1,'PARAMETERVALUE',1,1,'vas 25 2011 12:00:00:000AM','',3604177 select @p1, @p3, @p4, @p5
Run Code Online (Sandbox Code Playgroud)
大约有 100000 次这样的操作。理解的关键是“Entry No_”<@P8 意思是-下一个,下一个,下一个。这就是 NAV 在那里工作的方式:类似于桌子上的迭代。
正如您所看到的,对于 SQL 优化器来说,从未涵盖的索引 (Customer No_, Due Date, Currency Code.. ) 切换到聚集索引/主键 (Entry No_) 具有很大的诱惑力。并且在某一时刻决定使用聚集索引,然后服务器有IO操作的爆炸。在那之后,SQL Optimizer 决定返回未覆盖但最佳的索引......但黑色工作已完成:) 我们有 800 队列 10-15 分钟。
我需要注意的是,我对解决这个优化器问题不感兴趣(好吧,我感兴趣,但不在那里)。我有兴趣实现该会话不会使我的所有其他会话减慢到无法使用的程度。所以我很想知道如何配置 Assinhornous IO 或者至少知道这可能吗?
恕我直言,某些子系统(IO 控制器、windows、sql server)在决定创建如此庞大的队列时出错。我认为这是 sql server 配置或 IO 控制器中的错误,因为我以前从未听说过即使在大表上的“简单”聚集索引扫描也会产生巨大的队列。或者你已经有这种行为了?
我知道可能有一个更复杂的方案:当 SQL Server 根据需要启动 assync 调用时(例如,如果它需要 200 页 - 它启动 200 个 assync 读取),然后 Windows Assync IO API 决定异步启动它们或不是......这就是Windows Assync IO API的工作方式,但我真的不确定sql server是使用标准的windows assync api还是使用它自己的。
单个用户可以生成多个排队的 IO。用户数和队列中的 IO 数之间没有相关性。在查询中使用 select * 并且无法调整查询时,您将不得不求助于计划指南。
除了索引调优,没有办法控制SQL Server发送给IO子系统的IO。将聚集索引移动到一个或多个不同的列是否更有意义?
如果表不在内存中,聚簇索引扫描将产生大量 IO,因为它需要将数据从磁盘读入内存以扫描它,尤其是在表很大的情况下。