我有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。
测试数据:
该表越多,性能下降的索引越多:
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秒!
有人可以向我解释为什么这两种实现之间有如此大的区别吗?
我想念什么吗?
编辑: 该问题似乎与实体阅读有关:
看来,平均而言,对视图的查询需要的物理读取次数更少?
这是否意味着我仅依赖于服务器缓存的内容?有什么我可以改善的方法吗?
答案 0 :(得分:0)
如果计划相同且逻辑IO相同,则经过的时间将相同,除非存在诸如IO等待,锁定等待之类的等待。表中,您的页面并没有全部被缓存。
查询存储跟踪基于每个查询和每个计划的等待,因此您可以使用以下内容进行检查:
Control
这是否意味着我仅依赖于服务器缓存的内容? 是。查询性能始终取决于是否缓存数据。
有什么我可以改善的方法吗?
SQL Server将在页面缓存中保留最常用的页面,并且要缓存更多数据,您可以增加可用的内存量(通过增加DTU或vCore),也可以增加适合的行数页面。您可以在这里尝试做的一件事是COMPRESS JSON数据,并在需要时DECOMPRESS。这样可以缓存更多数据,但会增加读取时的CPU消耗。