如何强制 SQL Server 在 WHERE 子句之前处理 CONTAINS 子句?

Posted

技术标签:

【中文标题】如何强制 SQL Server 在 WHERE 子句之前处理 CONTAINS 子句?【英文标题】:How to force SQL Server to process CONTAINS clauses before WHERE clauses? 【发布时间】:2011-06-22 12:48:17 【问题描述】:

我有一个使用标准 WHERE 子句和全文索引 CONTAINS 子句的 SQL 查询。该查询是从代码动态构建的,并且包括可变数量的 WHERE 和 CONTAINS 子句。

为了使查询更快,在应用其余条件之前搜索全文索引非常重要。

但是,SQL Server 选择在 CONTAINS 子句之前处理 WHERE 子句,这会导致表扫描并且查询非常慢。

我可以使用两个查询和一个临时表来重写它。当我这样做时,查询的执行速度提高了 10 倍。但我不想在创建查询的代码中这样做,因为它太复杂了。

有没有办法强制 SQL Server 先处理 CONTAINS?我不能强制执行计划(USE PLAN),因为查询是动态构建的并且变化很大。

注意:我在 SQL Server 2005 和 SQL Server 2008 上遇到了同样的问题。

【问题讨论】:

这一点听起来有问题 - “查询是动态构建的并且变化很大” - 因为这可能意味着首先处理 CONTAINS 和之后的其他条件可能不会总是最优,所以即使你设法束缚了优化者的手,它也可能达不到预期的效果。 @Damien_The_Unbeliever:唯一完美的解决方案是修复 SQL Server 优化器本身。我不知道为什么它没有弄清楚首先处理 CONTAINS 会快得多。因此,任何其他解决方案都不会在所有情况下都是最佳的。但是,我知道在我们的案例中,首先处理 CONTAINS 会在大多数情况下更快。但你是对的;我不能保证。 【参考方案1】:

您可以像这样向优化器表明您的意图

SELECT
   *
FROM
    (
    SELECT *
    FROM


    WHERE
       CONTAINS
    ) T1
WHERE
   (normal conditions)

然而,SQL 是声明性的:你说what 你想要,而不是如何 去做。所以优化器可能会决定忽略上面的嵌套。

您可以在应用经典 WHERE 子句之前强制实现具有 CONTAINS 的派生表。我不会保证性能。

SELECT
   *
FROM
    (
    SELECT TOP 2000000000
       *
    FROM
       ....
    WHERE
       CONTAINS
    ORDER BY
       SomeID
    ) T1
WHERE
   (normal conditions)

【讨论】:

嗯,很好,如果 CONTAINS 结果的数量总是很少,我会建议一个循环连接提示,但这更干净,两全其美。 @gbn:如果你使用 CTE,那不是强制先评估吗? @Yuck:将 CTE 视为一个宏,就像我的派生表一样。也就是说,我可以改用 CTE。结果一样... @gbn:很有趣。我的印象是——显然是错误的——CTE 更像是一个隐式临时表而不是子查询。 @Yuck:它可以是递归的,但对于这种情况,它是一个让你的代码看起来更好的宏:-)【参考方案2】:

尝试在没有临时表的情况下使用 2 个查询:

SELECT * 
FROM table
WHERE id IN (
    SELECT id 
    FROM table 
    WHERE contains_criterias
) 
AND further_where_classes

【讨论】:

【参考方案3】:

正如我上面提到的,这不像@gbn 提出的 TOP 子句那样“实现”派生表的干净方式,但是循环连接提示强制执行评估顺序,并且过去对我有用(诚​​然,通常涉及两个不同的表)。但是有几个问题:

查询很丑 您仍然无法保证在加入之前不会评估其他 WHERE 参数(我很想看看您会得到什么)

既然你问了,那就是:

SELECT OriginalTable.XXX
FROM (
    SELECT XXX
    FROM OriginalTable
    WHERE 
        CONTAINS XXX
) AS ContainsCheck
INNER LOOP JOIN OriginalTable 
    ON ContainsCheck.PrimaryKeyColumns = OriginalTable.PrimaryKeyColumns
        AND OriginalTable.OtherWhereConditions = OtherValues

【讨论】:

感谢您花时间发布答案。

以上是关于如何强制 SQL Server 在 WHERE 子句之前处理 CONTAINS 子句?的主要内容,如果未能解决你的问题,请参考以下文章

WHERE 子句中的 SQL 查询子选择优化 (SQL Server)

SQL:如何在 SELECT 中从 WHERE 引用子表达式?

如何在 SQL 子查询中使用 WHERE EXISTS?

EXISTS 子句在 SQL Server 中如何工作?

如何在标准 SQL 的 WHERE 子句中使用 WITH 子查询作为选项列表

SQL 中 where 后面可不可以跟上子查询