为什么SQL Server在没有ORDER BY的情况下不能保证排序结果

再一次问好。在六月,OTUS再次启动“ MS SQL Server Developer”课程,传统上是在课程开始前夕,我们开始与您分享有关该主题的资料。




如果您的查询不包含ORDER BY,则不能确定结果的排序不会随时间变化。

当然,起初所有事情都是可以预见的,但是随着更改的发生(在索引,表,服务器配置,数据量方面),您可能会遇到一些不愉快的惊喜。

让我们从简单的事情开始:对Stack Overflow数据库的Users表执行SELECT。该表具有Id列的聚簇索引,该索引从1开始增加到一万亿。对于此查询,将按照聚集索引的顺序返回数据:



但是,如果在DisplayName和Location上创建了索引,则SQL Server突然决定使用新索引,而不是聚集索引:



这是执行计划:



为什么SQL Server决定使用此索引,尽管不需要对其进行排序。通过DisplayName和位置?因为此索引是需要获取的数据的最小副本。让我们通过以下方式查看索引的大小sp_BlitzIndex



聚集索引(CX / PK)大约有890万行,其大小为1.1 GB

在DisplayName的非聚集索引中,Location大约也有890万行,但其大小仅为368 MB如果需要进行扫描以获取查询结果,那么为什么不选择最小的数据源,因为它会更快。正是由于这个原因,SQL Server才这样做。

“是的,但是我的请求中包含WHERE。”


好的,现在我们有了DisplayName和Location的索引,让我们尝试一个查询来查找特定名称(DisplayName)。结果按DisplayName排序:



执行计划显示索引由DisplayName和Location使用:



但是,如果您查看不同的值,结果将不再按DisplayName排序:



SQL Server发现Alex拥有更合理的聚簇索引扫描而不是索引查找+键查找:



即使在这些非常简单的情况下,也不能保证SQL Server将始终使用所需的数据副本。

最近,我遇到了更为复杂的案例:

  • 删除查询中使用的索引
  • (Forced Parameterization), , SQL Server
  • (Compatibility Level) (Cardinality Estimator), .



.



All Articles