Joh*_* N. 2 sql-server index-tuning nonclustered-index sql-server-2016
我正在观察一个简单的语句,该语句正在查询一个表并访问多个索引来检索数据:
SELECT DISTINCT
feld16,
zahl4,
feld12,
feld19 FROM
object1 WHERE
(deleted = 0 or deleted IS NULL)
Run Code Online (Sandbox Code Playgroud)
查询执行计划可以在Brent Ozar 的 Paste The Plan网站上找到,图形表示如下:
该表由包含各种数据的 82 列组成。列中数据的分布deleted为:
deleted | Number of records
---------+-------------------
0 | 71'620'068
NULL | 10
a value | 59'673
Run Code Online (Sandbox Code Playgroud)
结果集包含大约。大约 6400 万行。7100 万行与搜索谓词匹配WHERE (deleted = 0 or deleted IS NULL)。这是因为DISTINCT遗漏了 700 万条记录。
为了加快速度,我正在考虑添加一个新索引。最初我以为我有足够的知识来添加足够的索引,但我开始重新审视自己。
以下哪个索引定义(可能)是适当的解决方案?
CREATE NONCLUSTERED INDEX [IDXNew] ON [schema_owner].[object1]
(
[deleted] ASC,
[feld16] ASC,
[zahl4] ASC,
[feld12] ASC,
[feld19] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = ON, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
Run Code Online (Sandbox Code Playgroud)
CREATE NONCLUSTERED INDEX [IDXNew] ON [schema_owner].[object1]
(
[feld16] ASC,
[zahl4] ASC,
[feld12] ASC,
[feld19] ASC
)
INCLUDE
(
[deleted] ASC
)
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = ON, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
Run Code Online (Sandbox Code Playgroud)
CREATE NONCLUSTERED INDEX [IDXNew] ON [schema_owner].[object1]
(
[deleted] ASC
)
INCLUDE(
[feld12],
[zahl4],
[feld16],
[feld19]
)
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
Run Code Online (Sandbox Code Playgroud)
.. 遵循第一个索引定义并包含所有列。在阅读INCLUDE索引创建部分时,我想到创建第二个索引。然后我想:为什么不向索引添加一个过滤器deleted = 0 or deleted IS NULL,然后开始猜测我对索引的了解。
SQL Server 2016 实例上运行一些跟踪标志。其中一些是 Microsoft PFE 在 PTOC 期间向我们推荐的。
<TraceFlag Value="2335" Scope="Global" /> -- Assume fixed amount of memory
<TraceFlag Value="2371" Scope="Global" /> -- Updates statistics in linear mode
<TraceFlag Value="4199" Scope="Global" /> -- Enable QO fixes
Run Code Online (Sandbox Code Playgroud)
CE 当前设置为以向后兼容模式运行:
CardinalityEstimationModelVersion="70"
Run Code Online (Sandbox Code Playgroud)
如果您特别想要优化以快速获得这些结果,那么一种方法是索引视图。
视图定义为
SELECT feld16,
zahl4,
feld12,
feld19,
COUNT_big(*) AS [count]
FROM object1
WHERE ( deleted = 0
OR deleted IS NULL )
GROUP BY feld16,
zahl4,
feld12,
feld19
Run Code Online (Sandbox Code Playgroud)
feld16, zahl4, feld12, feld19然后针对该视图创建的唯一聚集索引SELECT(可能带有NOEXPAND依赖于 SQL Server 版本的提示)可能是获取此数据的最快方法,因为所有数据都将提前预先计算。
在这种情况下,我不愿意使用索引视图,因为它仍然具有与原始表几乎一样多的行。
我会选择您的索引 1 并希望看到两个搜索( fordeleted = 0和deleted is null)在其他四列上合并在一起,然后输入到流聚合中以删除重复项,而无需任何排序或散列(或者理想情况下在合并)。
合并联合和流聚合之所以可能,是因为这两种查找都将按顺序返回行[feld16] ASC, [zahl4] ASC, [feld12] ASC, [feld19] ASC。
如果您没有获得所需的执行计划,则可能需要重写查询
SELECT feld16,
zahl4,
feld12,
feld19
FROM object1
WHERE ( deleted = 0 )
UNION
SELECT feld16,
zahl4,
feld12,
feld19
FROM object1
WHERE ( deleted IS NULL )
Run Code Online (Sandbox Code Playgroud)