9

我想知道是否有任何明智的方法来重写以下查询,以便优化器使用列上的索引?

CREATE PROCEDURE select_Proc1
    @Key1 int=0,
    @Key2 int=0
AS
BEGIN
    SELECT key3
    FROM Or_Table
    WHERE (@key1 = 0 OR Key1 = @Key1) AND
          (@key2 = 0 OR Key2 = @Key2)
END
GO

根据这篇文章如何优化使用Preethiviraj Kulasingham 的参数时“OR”子句的使用:

即使WHERE子句中的列被索引覆盖,SQL Server 也无法使用这些索引。这就提出了一个问题,是否有任何东西“阻止”了索引的使用?这个问题的答案是肯定的——罪魁祸首是参数和OR条件。

参数不包含在索引中,这意味着 SQL Server 不能使用任何索引来评估@key1=0(这个条件也适用于@key2=0)。

实际上,这意味着 SQL Server 不能使用索引来评估子句@key1=0 OR Key1= @key1(因为OR子句是两个条件所涵盖的行的并集)。同样的原则也适用于其他条款(re.key2)。这导致 SQL Server 得出结论,没有索引可用于提取行,让 SQL Server 使用下一个最佳方法 - 聚集索引扫描

如您所见,如果谓词在子句中被ORed,SQL 优化器将不会对列使用索引。WHERE此问题的一种解决方案是将IF所有可能的参数组合的查询与子句分开。

现在我的问题是——如果可能的组合不止三个或四个,我们应该怎么做?为每个组合编写单独的查询似乎不是一个合理的解决方案。

这个问题还有其他解决方法吗?

4

4 回答 4

12

SQL ServerOR在优化谓词方面不是很好。

用这个:

SELECT  key3
FROM    or_table
WHERE   @key1 = 0
        AND @key2 = 0
UNION ALL
SELECT  key3
FROM    or_table
WHERE   @key1 = 0
        AND @key2 <> 0
        AND key2 = @key2
UNION ALL
SELECT  key3
FROM    or_table
WHERE   @key2 = 0
        AND @key1 <> 0
        AND key1 = @key1
UNION ALL
SELECT  key3
FROM    or_table
WHERE   @key1 <> 0
        AND @key2 <> 0
        AND key1 = @key1
        AND key2 = @key2

SQL Server将在执行查询之前查看变量的值,并将优化冗余查询。

这意味着实际上只执行四个查询中的一个。

于 2010-01-29T11:40:29.260 回答
5

MSSQL 2008 有条件简化的优化语法,这里是

 Where (@key1 =0 OR Key1 =@Key1) AND
      (@key2 =0 OR Key2 =@Key2) option(recompile)

这将优化常量的使用

于 2010-01-29T11:52:15.497 回答
2

您是否尝试过表值函数?

CREATE FUNCTION select_func1 (  
    @Key1 int=0,
    @Key2 int=0
)
RETURNS TABLE 
AS RETURN (
    Select key3
    From Or_Table
    Where (@key1 =0 OR Key1 =@Key1) AND
          (@key2 =0 OR Key2 =@Key2)
)


select * from select_func1(1,2)
于 2010-01-29T12:48:10.310 回答
2

是的 -仔细使用动态 sql 将解决这个问题。有两种方法可以做到:

  1. 如果您是存储过程的“纯粹主义者”,则在存储过程中编写自定义查询字符串并执行该字符串。然后可以在每次执行时动态写入特定查询,以仅包括相关标准。

  2. 如果您对该 SQL 的位置很灵活,则可以(再次小心地)在应用程序中编写查询字符串并将其传递给服务器。

    当然,危险在于 SQL 注入。所以你必须非常小心数据是如何从客户端传递到动态 sql 语句的。

来自 Erland Sommarskog 的真正彻底和全面的文章

于 2010-01-30T00:35:12.280 回答