【发布时间】:2018-11-25 07:34:36
【问题描述】:
我有 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。
测试数据:
- 由 100 万个项目组成
- 分布在 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%'
但我想讨论的只是这个查询,因为最终这个查询之后的所有内容总是
SELECT TOP (1000) *
FROM [Schema1].[Item]
WHERE GroupId = 2
AND Category = 'Category4'
执行计划基本上只包含 100% Index Seek,估计 + 实际行数 = 1000(如预期)。这里一切看起来都很好。
但是对于 1.000.000 个项目,此查询仍然需要 2-3 秒 才能完成(没有查询缓存)。对于 100.000 个项目,这已经 。
这似乎违反了索引的对数可扩展性的逻辑?即使有我非常大的索引叶子(因为它们包含带有nvarchar(max) 的整个列,通常约为 500 字节),100.000 和 1.000.000 项之间仍然不应该有这么大的差异吗?
所以我接下来尝试的是创建一个索引视图
-
GroupId上的过滤器(因此它最多有 50.000 行) - 并且在 Category 上有一个索引(+包括所有列,与之前相同)
对于这个视图,这样的查询:
SELECT TOP (1000) *
FROM [Schema1].[Item_ViewGroupId1]
WHERE Category = 'Category4'
只需要!
谁能向我解释一下为什么这两种实现之间存在如此大的差异?
我错过了什么吗?
编辑: 问题似乎与物理读取有关:
- 慢:表“项目”。扫描计数 1,逻辑读取 362,物理读取 148,预读读取 547,lob 逻辑读取 0,lob 物理读取 0,lob 预读读取 0。
- 快速:表“项目”。扫描计数 1,逻辑读取 362,物理读取 0,预读读取 264,lob 逻辑读取 0,lob 物理读取 0,lob 预读读取 0
似乎平均而言,对视图的查询需要较少的物理读取?
这是否意味着我只依赖于服务器正在缓存的内容?有什么办法可以改善吗?
【问题讨论】:
-
您的
WHERE子句过滤 Category 和 ClassId 但索引位于 GroupId (未在查询中使用)和 Category 上,因此它没有用。尝试在 Caegory 和 ClassId 上创建索引。我希望这可以提高性能,但不如索引视图那么快。请注意,您需要ORDER BY和TOP。否则,返回的行是随机的。 -
当您使用 100,000 个项目进行测试时,是否返回了 1000 行?与每组 20 个组和 10 个类别一样,它可能只有 500 行。如果您 SET STATISTICS IO ON,查询是否显示逻辑读取的差异?
-
@DanGuzman:这只是一个错字,我修正了它。它正在搜索正确的索引。而且我对任何订单都不感兴趣。
-
@DavidBrowne-Microsoft:这两个查询的结果是相同的,除了查询的持续时间。我将研究逻辑读取。
-
@DavidBrowne-Microsoft:我做了一些进一步的测试,似乎物理读取是问题的原因?它们似乎很少出现在我的观点上。慢表“项目”。扫描计数 1,逻辑读取 362,物理读取 148,预读读取 547,lob 逻辑读取 0,lob 物理读取 0,lob 预读读取 0。FAST 表“项目”。扫描计数 1,逻辑读取 362,物理读取 0,预读读取 264,lob 逻辑读取 0,lob 物理读取 0,lob 预读读取 0。
标签: sql sql-server azure-sql-database