可查询的查询

ste*_*ten 8 performance sql-server t-sql query-performance

我希望这个问题很简单,我目前正在将一些脚本继承到我的项目中,由数据库管理员审查。显然以前从未这样做过,并且发现了很多问题。

我对此有点陌生,但我对 Sargable 和 Non-Sargable SQL 的理解是,违规函数正在列上运行,从而阻碍索引(假设存在索引),从而导致扫描列和性能受到打击。代码在输入中有几个函数,很多次要的东西,比如

Where a.date between 'inputdate' and dateadd(day,1,'inputdate')
Run Code Online (Sandbox Code Playgroud)

DBA 采取的立场是,任何WHERE子句中包含函数的查询都是不可复制的。我将放弃与他的问题,因为除了生气的管理员和我的访问受限之外,争论会让我无处可去。

但是为了知识起见,是否存在他是正确的并且WHERE从句中出现的任何功能都是问题的情况,无论功能或位置如何?

小智 8

正如 ypercube评论的那样

不,如果查询是你所展示的,他是完全错误的。它是相当sargable,因为它是。

您可以通过以下方式验证:

  • 创建一个带有 [Date] 列的简单测试表。
  • 插入大量日期不同的行。
  • 注意:在上面的“大量”和“不同的日期”中是一种预防措施,以确保您的查询具有足够的选择性。否则优化器在任何情况下都可能选择不使用您的索引。
  • 为您的查询生成一个查询计划(一次在日期列上有索引,一次没有)。
  • 您还可以使用 STATISTICS IO 来显示差异。
  • 如果您有足够的测试数据,则很容易观察到差异。

一旦获得证据,我建议您与 DBA 联系。但是,不要陷入争论。只需展示演示索引使用的测试和数据即可。

关键是你不想被迫向后弯腰以避免不存在的问题。

幸运的是,在您演示的情况下,将函数移到查询之外不会有问题。例如

DECLARE @FromDate date ='inputdate',
        @ToDate date = DATEADD(day, 1, @FromDate)
Run Code Online (Sandbox Code Playgroud)

事实上,从长远来看,上述内容甚至可能更易于维护。

但是,总有一天,您会遇到一些无法按照 DBA 的意愿进行微不足道更改的事情。如:

--Granted this probably belongs in a JOIN clause, but is primarily for illustrative purposes.
--Also the issue of sargability applies just as much to JOIN clauses as WHERE clauses
WHERE a.date >= b.date
  AND a.date < DATEADD(day, 1, b.date)
Run Code Online (Sandbox Code Playgroud)

使此函数脱离 WHERE 子句的唯一方法是预先计算另一列b.NextDay。这正是您需要 DBA 正确理解 Sargability 的原因。即上述:

  • 将能够利用 上的索引a.date
  • 但不能利用 上的索引b.date
  • 所以最具选择性的列/索引不应该应用一个函数,但另一个可以。
  • 试图破解 WHERE 子句中没有函数的解决方案会降低可维护性和性能。

如果您真的无法从 DBA 那里获得支持,那么以下可能会起作用并绕过他们的货物崇拜规则:

;WITH CTE_B AS (
    SELECT  b.Date, DATEADD(day, 1, b.DATE) AS NextDay
    FROM    b
    )
SELECT  ...
WHERE   a.Date >= CTE_B.Date
    AND a.Date < CTE_B.NextDay
Run Code Online (Sandbox Code Playgroud)

优化器几乎肯定会以与函数在WHERE子句中相同的方式优化它,因此您不应该受到性能影响。但这肯定是可维护性的不必要降低。