SQL性能-索引视图VS多列索引

时间:2018-11-24 21:00:44

标签: sql sql-server azure-sql-database

我有2个设置显示不同的性能,我想了解原因。 我必须写下很多信息,以便在上下文中所有这些都有意义。

TLTR:为什么我失去了多列索引的对数可扩展性?

表格:

CREATE TABLE Schema1.Item
(
    Id INT IDENTITY(1,1) PRIMARY KEY,
    UniqueName VARCHAR(20) NOT NULL UNIQUE,
    GroupId INT NOT NULL FOREIGN KEY REFERENCES Schema1.Group(Id),
    Category VARCHAR(200),
    Properties VARCHAR(max)
);

如果属性名称+属性值,最后一列“属性”包含一个JSON字典。其中的属性特定于GroupId。

测试数据:

  • 包含一百万个项目
  • 分为20组(每组约50000件)
  • 包含10个类别(每个组每个类别5000个项目)

该表越多,性能下降的索引越多:

CREATE NONCLUSTERED INDEX IX_GroupId_Category 
ON [Schema1].[Item] (GroupId, Category) 
INCLUDE(Id, UniqueName, Properties)

所以查询看起来像这样:

SELECT TOP (1000) *   
FROM [Schema1].[Item]
WHERE GroupId = 2
  AND Category = 'Category4'
  AND JSON_VALUE(Properties, '$."PropertyName"') LIKE '%PropertyValue%'

但是我要讨论的只是此查询,因为最终此查询之后的所有内容始终为<5000个项目:

SELECT TOP (1000) *   
FROM [Schema1].[Item]
WHERE GroupId = 2
  AND Category = 'Category4'

执行计划基本上仅由100%索引查找组成,估计+实际行数= 1000(按预期)。一切看起来都很好。

但是对于1.000.000个项目,此查询仍需要 2-3秒来完成(不带查询缓存)。拥有100.000个项目,已 <1秒

这似乎与索引的对数可扩展性逻辑背道而驰吗?即使我的索引叶子很大(因为它们包含nvarchar(max)的整个列,通常大约为500byte),在100.000和1.000.000之间的项目之间仍然应该不会有这么大的差异吗?

所以我接下来尝试的是创建一个索引视图

  • GroupId进行过滤(因此它最多可容纳50.000行)
  • 并在“类别”上有一个索引(+包括所有列,与以前相同)

对于此视图,查询如下:

SELECT TOP (1000) *   
FROM [Schema1].[Item_ViewGroupId1]    
WHERE Category = 'Category4'

只需要 <1秒

有人可以向我解释为什么这两种实现之间有如此大的区别吗?

我想念什么吗?


编辑: 该问题似乎与实体阅读有关:

  • 慢:表'Item'。扫描计数1,逻辑读362,物理读148,预读547,lob逻辑读0,lob物理读0,lob预读0。
  • 快速:表“ Item”。扫描计数1,逻辑读362,物理读0,预读264,lob逻辑读0,lob物理读0,lob预读0

看来,平均而言,对视图的查询需要的物理读取次数更少?

这是否意味着我仅依赖于服务器缓存的内容?有什么我可以改善的方法吗?

1 个答案:

答案 0 :(得分:0)

如果计划相同且逻辑IO相同,则经过的时间将相同,除非存在诸如IO等待,锁定等待之类的等待。表中,您的页面并没有全部被缓存。

查询存储跟踪基于每个查询和每个计划的等待,因此您可以使用以下内容进行检查:

Control
  

这是否意味着我仅依赖于服务器缓存的内容?   是。查询性能始终取决于是否缓存数据。

     

有什么我可以改善的方法吗?

SQL Server将在页面缓存中保留最常用的页面,并且要缓存更多数据,您可以增加可用的内存量(通过增加DTU或vCore),也可以增加适合的行数页面。您可以在这里尝试做的一件事是COMPRESS JSON数据,并在需要时DECOMPRESS。这样可以缓存更多数据,但会增加读取时的CPU消耗。