Sql server 如何强制SQL Server在WHERE子句之前处理CONTAINS子句?
我有一个SQL查询,它使用标准WHERE子句和全文索引CONTAINS子句。查询是根据代码动态构建的,包含数量可变的WHERE和CONTAINS子句 为了快速查询,在应用其余条件之前搜索全文索引是非常重要的 但是,SQLServer选择在CONTAINS子句之前处理WHERE子句,这会导致表扫描和查询速度非常慢 我可以使用两个查询和一个临时表来重写它。当我这样做时,查询的执行速度提高了10倍。但是我不想在创建查询的代码中这样做,因为它太复杂了 有没有一种方法可以强制SQL Server在处理其他内容之前先处理包含的内容?我不能强制执行计划(使用计划),因为查询是动态生成的,并且变化很大Sql server 如何强制SQL Server在WHERE子句之前处理CONTAINS子句?,sql-server,query-optimization,Sql Server,Query Optimization,我有一个SQL查询,它使用标准WHERE子句和全文索引CONTAINS子句。查询是根据代码动态构建的,包含数量可变的WHERE和CONTAINS子句 为了快速查询,在应用其余条件之前搜索全文索引是非常重要的 但是,SQLServer选择在CONTAINS子句之前处理WHERE子句,这会导致表扫描和查询速度非常慢 我可以使用两个查询和一个临时表来重写它。当我这样做时,查询的执行速度提高了10倍。但是我不想在创建查询的代码中这样做,因为它太复杂了 有没有一种方法可以强制SQL Server在处理其他
注意:我在SQL Server 2005和SQL Server 2008上遇到了相同的问题。尝试使用两个不带临时表的查询:
SELECT *
FROM table
WHERE id IN (
SELECT id
FROM table
WHERE contains_criterias
)
AND further_where_classes
你可以像这样向乐观主义者表明你的意图
SELECT
*
FROM
(
SELECT *
FROM
WHERE
CONTAINS
) T1
WHERE
(normal conditions)
然而,SQL是声明性的:你说你想要什么,而不是怎么做。因此,乐观主义者可能会决定忽略上面的嵌套
可以在应用经典WHERE子句之前,强制将包含的派生表具体化。我不能保证性能
SELECT
*
FROM
(
SELECT TOP 2000000000
*
FROM
....
WHERE
CONTAINS
ORDER BY
SomeID
) T1
WHERE
(normal conditions)
正如我前面提到的,这并不像@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
嗯,好的,我会建议一个循环连接提示,如果包含的结果总是已知的是小的,但是这是更干净的,最好的两个世界。@ GBN:如果你使用CTE不首先强制评估?@ YCK:考虑CTE一个宏就像我的派生表。也就是说,我可以用CTE来代替。同样的结果…@gbn:有趣。我有一种明显错误的印象,认为CTE更像是一个隐式临时表,而不是一个子查询。@恶心:递归时可以,但在这种情况下,它是一个宏,可以使代码看起来更好:-)这听起来有点问题-“查询是动态构建的,变化很大”-因为这可能意味着先处理
包含,然后再处理其他条件可能并不总是最优的,所以即使您设法束缚了优化器的手脚,也可能没有达到预期的效果。@Damien_不相信者:唯一完美的解决方案是修复SQL Server优化器本身。我不知道为什么它没有发现首先处理包含的内容会快得多。因此,任何其他解决方案都不会在所有情况下都是最优的。但是,我知道在我们的情况下,大多数情况下,先处理CONTAINS会更快。但你是对的;我不能保证。谢谢你花时间发布答案。