tre*_*nja 7 sql-server clustered-index sql-server-2008-r2 index-tuning
我被要求查看一张非常繁忙的表格并找出任何需要改进的地方。
我只能更改索引表的能力非常有限。
sys.dm_db_index_usage_statsDMV,在过去 7 周内每周运行两次。此表上的当前聚集索引有五列:
我的理解是聚簇索引应该坚持以下属性。 来源
当前的聚集索引不是这些。
所以我的假设是用Id列上的聚集索引来纠正这个问题- 一个不是身份但通过计数器表维护的整数(读取值,加 1,更新计数器表)。
我在 上创建了一个聚集索引Id,不使用主键,因为我相信添加 guid 和 company 列不会给我任何好处。
然后我创建了一个非聚集索引,其中包含 Company、Region 和 3 标志。在测试环境中,统计数据看起来不错,user_updates但较低等。但是针对该表的应用程序的整体性能很糟糕。针对该表的最常见查询是:
SELECT *
FROM table
WHERE ID = 1234;
Run Code Online (Sandbox Code Playgroud)
和
SELECT *
FROM table
WHERE Company = 'company'
AND Region = 'region'
AND flagA= 'A'
AND flagB = 'B'
AND flagC = 'C';
Run Code Online (Sandbox Code Playgroud)
我的理解是,如果聚集索引位于非静态值上,它需要不断地重新组织自身和其他非聚集索引,此时我们还有 40 多个……稍后将被删除。我不会在那里看到收益吗?
SELECT *在上面的例子中写了简洁。Id. 我想重新尝试使用 Company、Region 和 Id 作为 CI,但将三个标志排除在外。我错过了什么?
上述聚集索引规则是否有例外?
选择聚集索引的一般指南很好,但有时需要考虑其他注意事项。有时,这些额外因素可能比一般“规则”更重要。
您的场景有些“特殊”,因为您有一个非常宽的表,并且有一组查询请求一组(大概)不可预测的列,尽管查询谓词通常是相同的。
最初的聚集索引安排对于更改数据的操作来说可能代价高昂,因为更改聚集键的任何部分都意味着更改所有非聚集索引。此外,在日志生成方面,物理移动整行的成本很高,尤其是在发生页面拆分的情况下。
也就是说,一旦聚集索引被修改并分割了相当多的部分,它将包含相当多的可用空间,使未来的移动不那么密集,就像一开始就设置了合理的填充因子一样,并保持为正常索引维护的一部分。
您的生产系统似乎已经陷入某种平衡,其中页面分割以稳定、合理的速率发生。非聚集索引维护仍然相对昂贵,但这似乎不是一个主导因素。
原始索引安排的关键优点是:
聚集索引(Company、Region、FlagA、FlagB、FlagC)与以下谓词匹配:
SELECT {unpredictable column list}
FROM table
WHERE Company = 'company'
AND Region = 'region'
AND flagA= 'A'
AND flagB = 'B'
AND flagC = 'C';
Run Code Online (Sandbox Code Playgroud)
...同时提供对选择列表中列出的任何列的访问。
查询形式:
SELECT *
FROM table
WHERE ID = 1234;
Run Code Online (Sandbox Code Playgroud)
...非聚集主键充分支持。此查询始终返回单行,因此在非聚集索引中定位该行后,只需要通过聚集索引进行一次查找。
更改为 上的聚集索引ID以及 (Company、Region、FlagA、FlagB、FlagC) 上的非聚集索引使第二个查询的效率更高一些(消除每个查询的一次查找),但使第一个查询的效率大大降低(替换零)查找~5000)。
此外,优化器很可能选择根本不使用非聚集索引,估计对表进行完整扫描会比 5000 次查找更便宜。
您最好暂时保留两个主要索引,同时整理 40 多个非聚集索引,并分析所需的最小覆盖非聚集索引集的工作负载。一旦获得该数据,您将能够更好地考虑基本指数变化。
您可能还想检查此表的现有监控和维护例程。在许多情况下,如果表的填充因子能够在下一个维护窗口到来之前防止出现严重的页面拆分,那么“打破规则”的聚集索引就可以了。
| 归档时间: |
|
| 查看次数: |
148 次 |
| 最近记录: |