【问题标题】:SQL: short-circuiting not working. "Null or empty full-text predicate" after upgrading to SQL Server 2012SQL:短路不起作用。升级到 SQL Server 2012 后出现“空全文谓词”
【发布时间】:2014-01-01 02:55:54
【问题描述】:

我在 SQL Server 2005 中有以下查询,它运行良好:

DECLARE @venuename NVARCHAR(100)
DECLARE @town NVARCHAR(100)

SET @venuename =  NULL -- normally these are parameters in the stored proc.
SET @town = 'London'

SELECT COUNT(*) FROM dbo.Venue
WHERE 
    (@VenueName IS NULL OR CONTAINS((Venue.VenueName), @VenueName))
AND 
    (@Town IS NULL OR Town LIKE @Town + '%')

当为参数传递空值时,它使用短路(实际 SP 中的参数比我的示例中显示的要多)。

但是在升级到 SQL 2012 后,使用为 @VenueName 传递的 NULL 运行此查询失败,并出现错误“Null or empty full-text predicate”,因为 SQL Server 似乎正在运行(或评估) @VenueName 的 CONTAINS 语句,即使 @VenueName 设置为 NULL。

有没有办法在 2012 年使用短路,或者这不再可能?我讨厌不得不重写我所有的 SP,因为多年来我们已经在跨多个项目的数十个存储过程中使用了这种技术。

【问题讨论】:

    标签: sql sql-server tsql stored-procedures sql-server-2012


    【解决方案1】:

    查看此线程:OR Operator Short-circuit in SQL Server 在 SQL Server 中,不能保证 OR 子句会提前中断。一直都是这样,所以我猜你很幸运能够与 SQL Server 2005 一起使用。

    要解决您的问题,请考虑在每次向 CONTAINS 函数提供可能为 NULL 的参数值时使用 ISNULL 函数。

    【讨论】:

    • 好计划,但如何?因为 ISNULL 似乎不能在 CONTAINS 函数中使用 - 它只会给出语法错误。 :(
    • 似乎这个解决方案是不可能的(直接),所以@Dhaval 的答案可能会更好。 stackoverflow.com/questions/3781532/…
    • 这样的东西应该可以解决问题,但不可否认,它不是很优雅:CONTAINS((Venue.VenueName), ISNULL(@VenueName,'<some-random-string-that-does-not-appear-in-any-VenueName>'))
    • 这给出了一个语法错误。您不能在 CONTAINS 中使用 ISNULL。请参阅我上一篇中的链接。评论。
    • 啊,谢谢 - 我不知道。当搜索词为空时,重写查询以完全避免全文搜索似乎并不容易。
    【解决方案2】:

    这是完美的答案。

    让我们看看这两个陈述:

    IF (CONDITION 1) OR (CONDITION 2)
    ..
    IF (CONDITION 3) AND (CONDITION 4)
    ...
    
    • 如果 CONDITION 1 为 TRUE,是否会检查 CONDITION 2?
    • 如果 CONDITION 3 为 FALSE,是否会检查 CONDITION 4?

    WHERE 的条件如何:SQL Server 引擎是否优化了WHERE 子句中的所有条件?程序员是否应该按正确的顺序放置条件以确保 SQL Server 优化器以正确的方式解决它?

    添加:
    感谢 Jack 的链接,来自 t-sql 代码的惊喜:

    IF  1/0 = 1 OR 1 = 1
          SELECT 'True' AS result
    ELSE
          SELECT 'False' AS result
    IF  1/0 = 1 AND 1 = 0
          SELECT 'True' AS result
    ELSE
          SELECT 'False' AS result
    

    在这种情况下不会引发除以零异常。

    结论:

    如果 C++/C#/VB 有短路,为什么 SQL Server 不能有它?

    要真正回答这个问题,让我们来看看两者是如何在条件下工作的。 C++/C#/VB 都在语言规范中定义了短路以加速代码执行。为什么要在第一个条件已经为真时评估 N OR 条件,或者在第一个条件已经为假时评估 M AND 条件。

    作为开发人员,我们必须意识到 SQL Server 的工作方式不同。这是一个基于成本的系统。为了获得我们查询的最佳执行计划,查询处理器必须评估每个 where 条件并为其分配成本。然后将这些成本作为一个整体进行评估,以形成一个阈值,该阈值必须低于 SQL Server 为一个好的计划而定义的阈值。如果成本低于定义的阈值,则使用计划,如果不是,则使用不同的条件成本组合再次重复整个过程。这里的成本是扫描或查找或合并连接或哈希连接等......因此,C++/C#/VB 中可用的短路是不可能的。您可能认为在列上强制使用索引算作短路,但事实并非如此。它只强制使用该索引,从而缩短可能的执行计划列表。该系统仍以成本为基础。

    作为开发人员,您必须意识到 SQL Server 不会像在其他编程语言中那样进行短路,而且您无法强制这样做。

    【讨论】:

    • 这不是“完美答案”,因为它所做的只是解释快捷方式不起作用(我已经在我的问题中提出了这个问题!虽然有趣并且可能有用,但它并不适用无论如何回答我的问题或解决我的直接问题。抱歉。
    【解决方案3】:

    我对 sql 2012 不太了解,但请您尝试关注

    DECLARE @venuename NVARCHAR(100)  
    DECLARE @town NVARCHAR(100)
    
    SET @venuename =  '""' -- -- **Yes '""' instead of null**.
    SET @town = 'London'
    
    SELECT COUNT(*) FROM dbo.Venue
    WHERE 
        (@VenueName ='""' OR CONTAINS((Venue.VenueName), @VenueName))
    AND 
        (@Town IS NULL OR Town LIKE @Town + '%')
    

    【讨论】:

    • 这行得通,但查询计划显示它实际上是在执行全文搜索。如果可能的话,我试图避免这种情况(因此短路)。
    猜你喜欢
    • 2015-02-05
    • 2013-03-16
    • 2020-10-11
    • 2012-09-06
    • 1970-01-01
    • 1970-01-01
    • 2016-02-14
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多