SQL 2008:在不需要时防止在查询中进行全文查找

发布于 2024-12-14 01:26:28 字数 846 浏览 2 评论 0原文

通过研究这个具体情况,我发现 SQL 中的逻辑运算符并没有短路。

我通常在 where 子句中按照这些思路做一些事情(通常在处理搜索查询时):

WHERE
   (@Description IS NULL OR @Description = myTable.Description)

即使在本例中它没有短路,也并不重要。但是,在处理全文搜索功能时,这确实很重要。如果该查询的第二部分是 CONTAINS(myTable.Description, @Description),则它将不起作用,因为该变量不是这些函数允许为 null 或为空。

我发现 CASEWHEN 语句是按顺序执行的,因此我可以像这样更改查询,以确保仅在需要时调用全文查找,同时更改当变量为 null 时,将其从 null 更改为 '""' 以允许执行查询:

WHERE
   (CASE WHEN @Description = '""' THEN 1 WHEN CONTAINS(myTable.Description, @Description) THEN 1 ELSE 0 END = 1)

上面的代码应该阻止全文查询片段执行,除非确实存在要搜索的值。

我的问题是,如果我运行 @Description 为 '""' 的查询,则执行计划中仍然有相当多的时间花费在处理聚集索引查找和全文匹配上,即使该表并且搜索最终根本没有被使用:有什么办法可以避免这种情况吗?

我试图将其从硬编码的动态查询中取出并放入存储过程中,但如果该过程最终变慢,我不确定我是否可以证明它是合理的。

From working on this specific situation, it was news to me that the logic operators are not short circuited in SQL.

I routinely do something along these lines in the where clause (usually when dealing with search queries):

WHERE
   (@Description IS NULL OR @Description = myTable.Description)

Which, even if it's not short-circuited in this example, doesn't really matter. However, when dealing with the fulltext search functions, it does matter.. If the second part of that query was CONTAINS(myTable.Description, @Description), it wouldn't work because the variable is not allowed to be null or empty for these functions.

I found out the WHEN statements of CASE are executed in order, so I can change my query like so to ensure the fulltext lookup is only called when needed, along with changing the variable from null to '""' when it is null to allow the query to execute:

WHERE
   (CASE WHEN @Description = '""' THEN 1 WHEN CONTAINS(myTable.Description, @Description) THEN 1 ELSE 0 END = 1)

The above code should prevent the full-text query piece from executing unless there is actually a value to search with.

My question is, if I run this query where @Description is '""', there is still quite a bit of time in the execution plan spent dealing with clustered index seeks and fulltextmatch, even though that table and search does not end up being used at all: is there any way to avoid this?

I'm trying to get this out of a hardcoded dynamic query and into a stored procedure, but if the procedure ends up being slower, I'm not sure I can justify it.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

得不到的就毁灭 2024-12-21 01:26:28

这并不理想,但也许这样的东西会起作用:

IF @Description = ''
BEGIN 
     SELECT ...
END
ELSE
BEGIN
     SELECT ...
     WHERE CONTAINS(mytable.description, @Description)
END

这样你就可以避免 mysql 并且在不需要时运行 FT 扫描。

作为一些一般性说明,我通常发现 CONTAINSTABLE 更快一些。另外,由于无论您使用我的解决方案还是您的解决方案,查询计划都会有很大不同,因此请注意 参数嗅探。参数嗅探是指优化器根据传入的特定参数值构建计划。

It's not ideal, but maybe something like this would work:

IF @Description = ''
BEGIN 
     SELECT ...
END
ELSE
BEGIN
     SELECT ...
     WHERE CONTAINS(mytable.description, @Description)
END

That way you avoid mysql and also running the FT scan when it's not needed.

As a few general notes, I usually find CONTAINSTABLE to be a bit faster. Also, since the query plan is going to be very different whether you're using my solution or yours, watch out for parameter sniffing. Parameter sniffing is when the optimizer builds a plan based on a passed in specific parameter value.

身边 2024-12-21 01:26:28

如果其他人遇到这样的情况,这就是我最终所做的,这与 M_M 的意思非常接近;我分解了全文并将它们放在分支后面:

DECLARE @TableBfullSearch TABLE (TableAId int)
IF(@TableBSearchInfo IS NOT NULL)
   INSERT INTO @TableBfullSearch
   SELECT
      TableAId
   FROM
      TableB
   WHERE
   ...(fulltext search)...

DECLARE @TableCfullSearch TABLE (TableAId int)
IF(@TableCSearchInfo IS NOT NULL)
   INSERT INTO @TableCfullSearch
   SELECT
      TableAId
   FROM
      TableC
   WHERE
   ...(fulltext search)...

--main query with this addition in the where clause
SELECT
  ...
FROM
   TableA
WHERE
   ...
   AND (@TableBSearchInfo IS NULL OR TableAId IN (SELECT TableAId FROM @TableBfullSearch))
   AND (@TableCSearchInfo IS NULL OR TableAId IN (SELECT TableAId FROM @TableCfullSearch))

我认为这可能是在没有某种动态查询的情况下得到的最好结果

In case anyone else runs into a scenario like this, this is what I ended up doing, which is pretty close to what M_M was getting at; I broke away the full-text pieces and placed them behind branches:

DECLARE @TableBfullSearch TABLE (TableAId int)
IF(@TableBSearchInfo IS NOT NULL)
   INSERT INTO @TableBfullSearch
   SELECT
      TableAId
   FROM
      TableB
   WHERE
   ...(fulltext search)...

DECLARE @TableCfullSearch TABLE (TableAId int)
IF(@TableCSearchInfo IS NOT NULL)
   INSERT INTO @TableCfullSearch
   SELECT
      TableAId
   FROM
      TableC
   WHERE
   ...(fulltext search)...

--main query with this addition in the where clause
SELECT
  ...
FROM
   TableA
WHERE
   ...
   AND (@TableBSearchInfo IS NULL OR TableAId IN (SELECT TableAId FROM @TableBfullSearch))
   AND (@TableCSearchInfo IS NULL OR TableAId IN (SELECT TableAId FROM @TableCfullSearch))

I think that's probably about as good as it'll get without some sort of dynamic query

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文