我在 SQL Server 2017 执行计划中看到了这个警告:
警告:操作导致残留 IO [原文如此]。实际读取的行数为 (3,321,318),但返回的行数为 40。
下面是 SQLSentry PlanExplorer 的一个片段:
为了改进代码,我添加了一个非聚集索引,以便 SQL Server 可以获取相关行。它工作正常,但通常会有太多(大)列包含在索引中。它看起来像这样:
如果我只添加索引,没有包含列,它看起来像这样,如果我强制使用索引:
显然,SQL Server 认为键查找比残余 I/O 昂贵得多。我有一个没有太多测试数据的测试设置(还没有),但是当代码投入生产时,它需要处理更多的数据,所以我相当确定需要某种非聚集索引。
当您在 SSD 上运行时,关键查找真的那么昂贵吗,我必须创建全脂索引(包含很多包含列)?
执行计划: https ://www.brentozar.com/pastetheplan/?id=SJtiRte2X它是长存储过程的一部分。寻找IX_BatchNo_DeviceNo_CreatedUTC
。
优化器使用的成本模型正是:模型。它在广泛的工作负载、广泛的数据库设计和广泛的硬件上产生一般良好的结果。
您通常不应假设单个成本估算与特定硬件配置的运行时性能密切相关。成本计算的重点是允许优化器在相同逻辑操作的候选物理替代方案之间做出有根据的选择。
当您真正深入了解细节时,熟练的数据库专业人员(有时间调整重要查询)通常可以做得更好。就此而言,您可以将优化器的计划选择视为一个很好的起点。在大多数情况下,该起点也将是终点,因为找到的解决方案已经足够好。
根据我的经验(和意见),SQL Server 查询优化器的查找成本比我希望的要高。这在很大程度上是随机物理 I/O 与顺序访问相比比今天的情况更昂贵的时代的遗留问题。
尽管如此,即使在 SSD 上查找也可能很昂贵,或者最终甚至在仅从内存中读取时也是如此。遍历 b 树结构不是免费的。显然,当你做更多的事情时,成本就会增加。
包含的列非常适合读取繁重的 OLTP 工作负载,其中索引空间使用和更新成本与运行时读取性能之间的权衡是有意义的。围绕计划稳定性还需要权衡取舍。完全覆盖的索引避免了优化器的成本模型何时可能从一种替代方案转换到另一种替代方案的问题。
只有您可以决定在您的情况下权衡是否值得。在具有代表性的数据样本上测试两种备选方案,并做出明智的选择。
在您添加的问题评论中:
不,优化器确实考虑了剩余 I/O 的成本。实际上,就优化器而言,非 SARGable 谓词在单独的过滤器中进行评估。在优化后重写期间,此过滤器作为残差被推入查找或扫描中。