排除查询性能不佳故障:基数估计

SQL Server 中的查询优化器是基于开销的。这意味着它将选择执行具有最低估计处理开销的查询计划。查询优化器基于以下两个主要因素来确定执行查询计划的开销:

  • 查询计划每个级别上处理的总行数,称为该计划的基数。

  • 由查询中所使用的运算符规定的算法的开销模式。

第一个因素(基数)用作第二个因素(开销模式)的输入参数。因此,增大基数将减少估计开销,从而加快执行计划。

SQL Server 主要通过创建索引或统计信息时所创建的直方图,以手动或自动方式估计基数。有时,SQL Server 还使用查询的约束信息和逻辑重写来确定基数。

在下列情况下,SQL Server 无法精确计算基数。这将使开销计算不准确,可能导致生成不理想的查询计划。避免在查询中使用这些构造可以提高查询性能。有时,使用查询表达式或其他措施也可以提高查询性能,如下所述:

  • 带谓词的查询,这些查询在同一表的不同列之间使用比较运算符。

  • 带谓词的查询,这些查询使用运算符且下列任何一种情况为 True:

    • 运算符两侧所涉及的列中没有统计信息。

    • 统计信息中值的分布不均匀,但查询将查找高选择性的值集。特别是,当运算符是除相等 (=) 运算符以外的任何其他运算符时,这种情况可能为 True。

    • 谓词使用不等于 (!=) 比较运算符或 NOT 逻辑运算符。

  • 使用任意 SQL Server 内置函数或标量值用户定义函数(其参数不是常量值)的查询。

  • 包含通过算术或字符串串联运算符联接的列的查询。

  • 比较在编译或优化查询时其值未知的变量的查询。

下列措施可用于尝试提高这些类型的查询的性能:

  • 对查询中所包含的列生成有用的索引或统计信息。有关详细信息,请参阅设计索引使用统计信息提高查询性能

  • 如果查询使用比较或算术运算符比较或组合两个或多个列,则考虑使用计算列并重写查询。例如,以下查询比较两列中的值:

    SELECT * FROM MyTable
    WHERE MyTable.Col1 > MyTable.Col2
    

    如果将计算列 Col3 添加到用于计算 Col1Col2 之间的差(即 Col1 减去 Col2)的 MyTable,可能会提高性能。然后,重写查询:

    SELECT * FROM MyTable
    WHERE Col3 > 0
    

    如果对 MyTable.Col3 生成索引,则性能可能会有更大的提高。