将自由文本搜索与另一个条件相结合很慢

时间:2013-05-08 10:41:05

标签: sql-server full-text-search

我在SQL Server 2008R2上的一个简单表上有一个自由文本目录:

CREATE FULLTEXT CATALOG customer_catalog;
CREATE FULLTEXT INDEX ON customer
 ( 
   name1
 ) 
  KEY INDEX customer_pk
  ON customer_catalog;
ALTER FULLTEXT INDEX ON customer START UPDATE POPULATION;

如果我执行以下三个查询,前两个查询几乎立即返回,而最后一个查询在具有100,000条记录的表上花费约14秒:

SELECT
        customer_id
    FROM
        customer
    WHERE
        CONTAINS(customer.*, 'nomatch');

SELECT
        customer_id
    FROM
        customer
    WHERE
        customer.customer_id = 0;

SELECT
        customer_id
    FROM
        customer
    WHERE
        CONTAINS(customer.*, 'nomatch')
            OR customer.customer_id = 0;

以下是查询计划:

enter image description here

为什么第三个查询这么慢?我可以做些什么来改进它,还是需要拆分查询?

3 个答案:

答案 0 :(得分:3)

很难说为什么,但似乎SQL Server正在选择效率低下的查询计划。以下是一些建议:

更新表格中的统计信息:

UPDATE STATISTICS dbo.customer

统计信息是最新的,您可以再次尝试查询,看看是否有改进。

对于合并的OR语句,SQL Server正在使用索引扫描而不是搜索。您可以尝试FORCESEEK提示,看看是否有所作为:

SELECT customer_id
FROM customer WITH (FORCESEEK)
WHERE CONTAINS(customer.*, 'nomatch')
OR customer.customer_id = 0;

正如您所提到的,另一个选项是拆分语句。以下UNION的效果与前两个结果相同:

SELECT customer_id FROM customer
WHERE CONTAINS(customer.*, 'nomatch')

UNION

SELECT customer_id FROM customer
WHERE customer.customer_id = 0

更新 - 将上述查询更改为UNION而不是UNION ALL

正如@PondLife在评论中指出的那样,我打算在上面的查询中执行UNION而不是UNION ALL。在考虑之后,我也尝试了UNION ALL,它似乎更快。这假设您不关心重复的ID:

SELECT customer_id FROM customer
WHERE CONTAINS(customer.*, 'nomatch')

UNION ALL

SELECT customer_id FROM customer
WHERE customer.customer_id = 0

答案 1 :(得分:3)

“OR”逻辑条件通常会使查询运行得非常缓慢:/ 通常,最好的选择是使用UNION(ALL)。

在你的情况下,我对你的用法非常好奇

SELECT
    customer_id
FROM
    customer
WHERE
    customer.customer_id = 0;

它只会导致零的列表(可能为空)。 是否计算(!)有多少客户的id = 0? 是否检查任何客户的ID是否为0?

如果不计算零但是要知道它们是否为任何,那么这个查询应该是有效的:

SELECT
    customer_id
FROM
    customer
WHERE
    CONTAINS(customer.*, 'nomatch')
    AND customer.customer_id <> 0
UNION ALL
SELECT TOP(1)
    0
FROM
    customer
WHERE
    customer.customer_id = 0

否则有效的查询就是这个:

SELECT
    customer_id
FROM
    customer
WHERE
    CONTAINS(customer.*, 'nomatch')
    AND customer.customer_id <> 0
UNION ALL
SELECT
    0
FROM
    customer
WHERE
    customer.customer_id = 0

(我刚刚删除了TOP条款)

答案 2 :(得分:2)

根据您的MS SQL 2008 R2服务包版本,您的问题可能与以下Microsoft Connect问题有关:Full-text performance with "mixed queries"

根据MS Connect条目,在安装SQL Server 2008 R2的最新累积更新包后问题应该消失。