Azure SQL Server 上的空表上的 SELECT 即使使用非聚集索引也需要很长时间才能完成

问题描述 投票:0回答:1

情况:Azure SQL Server 数据库(20 个 DTU)使用了大约 20% 的空间。没有其他进程正在运行查询,计算利用率图表在 0%.

上显示一条实线

我们有一个大约有 80 列的空表。没有创建索引。我们有这样的查询

SELECT column1,
       column2,
       ...
       columnN
FROM table
WHERE column1 = "some" 
  AND column2 = "something" 
  AND column3 = "something" 
  AND column4 = "something"

WHERE
子句上,我们使用了 4 列(其中一列是
Timestamp
列)。

当我们运行这个查询时,运行几分钟后,我们终止进程,因为它永远不会结束,数据库 CPU 为 100%。正如我所说,桌子是空的。

我创建了一个这样的非聚集索引:

CREATE NONCLUSTERED INDEX [index_name] 
ON [dbo].[table] ([column1] ASC, [column2] ASC, 
                  [column3] ASC, [column4] ASC)
         WITH (STATISTICS_NORECOMPUTE = OFF, DROP_EXISTING = OFF, 
               ONLINE = OFF, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY]
GO

创建索引后,相同的查询需要几分钟才能完成(同样,CPU 使用率为 100%)。查询执行计划只是显示一个

table scan
。我的第一个问题是,为什么我们得到
table scan
而不是
index scan
?该索引包含
WHERE
子句中包含的 4 列。

但是,如果我创建相同的索引但作为

CLUSTERED
索引,查询几乎立即完成并且执行计划显示
index clustered seek
.

为什么对空表的查询需要聚集索引来得出空表的结论?为什么有一个非集群的还不够?

任何帮助将不胜感激。

更新。

带有非聚集索引的执行计划。注意:因为我已经创建了一个聚簇索引并将其删除以显示此执行计划,所以现在它不再是索引扫描了。这是索引查找。所以看起来问题确实是堆问题。

创建聚簇索引后的执行计划是here.

sql-server azure-sql-database
1个回答
0
投票

估计的计划没有证实这一点,但这几乎可以肯定是这样一种情况,即堆曾经很大并且仍然持有许多页面,这些页面自从这些行被删除后还没有被释放。

这种症状在堆中尤为普遍,正如 Martin 指出的那样,Paul Randal 在这里写道:

添加聚簇索引解决了这个问题,因为它必须完全重建表,然后才能最终释放空页。即使您删除聚簇索引并添加非聚簇索引,症状仍然会消失,因为那些被释放的页面永远消失了。但是,如果您保留 just 非聚集索引,并随着时间的推移填满表,然后再次清除它,您将再次遇到同样的问题。

Only 添加非聚集索引(不首先创建聚集索引或以其他方式强制重建)并不能解决问题,因为它不像添加聚集索引那样重建表。所以页面仍然没有被释放。

您还可以通过删除空表并重新创建它(如果它实际上是空的)来解决症状,或者 - 无论它是否为空 - 手动重建它:

ALTER TABLE dbo.MyHeap REBUILD;

但是,为了完全防止症状发生,我只是不会使用堆。创建聚簇索引并保留它.

© www.soinside.com 2019 - 2024. All rights reserved.