排除查询性能不佳故障:基数估计
SQL Server 中的查询优化器是基于开销的。这意味着它将选择执行具有最低估计处理开销的查询计划。查询优化器基于以下两个主要因素来确定执行查询计划的开销:
查询计划每个级别上处理的总行数,称为该计划的基数。
由查询中所使用的运算符规定的算法的开销模式。
第一个因素(基数)用作第二个因素(开销模式)的输入参数。因此,增大基数将减少估计开销,从而加快执行计划。
SQL Server 主要通过创建索引或统计信息时所创建的直方图,以手动或自动方式估计基数。有时,SQL Server 还使用查询的约束信息和逻辑重写来确定基数。
在下列情况下,SQL Server 无法精确计算基数。这将使开销计算不准确,可能导致生成不理想的查询计划。避免在查询中使用这些构造可以提高查询性能。有时,使用查询表达式或其他措施也可以提高查询性能,如下所述:
带谓词的查询,这些查询在同一表的不同列之间使用比较运算符。
带谓词的查询,这些查询使用运算符且下列任何一种情况为 True:
运算符两侧所涉及的列中没有统计信息。
统计信息中值的分布不均匀,但查询将查找高选择性的值集。特别是,当运算符是除相等 (=) 运算符以外的任何其他运算符时,这种情况可能为 True。
谓词使用不等于 (!=) 比较运算符或 NOT 逻辑运算符。
使用任意 SQL Server 内置函数或标量值用户定义函数(其参数不是常量值)的查询。
包含通过算术或字符串串联运算符联接的列的查询。
比较在编译或优化查询时其值未知的变量的查询。
下列措施可用于尝试提高这些类型的查询的性能:
对查询中所包含的列生成有用的索引或统计信息。有关详细信息,请参阅设计索引和使用统计信息提高查询性能。
如果查询使用比较或算术运算符比较或组合两个或多个列,则考虑使用计算列并重写查询。例如,以下查询比较两列中的值:
SELECT * FROM MyTable WHERE MyTable.Col1 > MyTable.Col2
如果将计算列 Col3 添加到用于计算 Col1 和 Col2 之间的差(即 Col1 减去 Col2)的 MyTable,可能会提高性能。然后,重写查询:
SELECT * FROM MyTable WHERE Col3 > 0
如果对 MyTable.Col3 生成索引,则性能可能会有更大的提高。