我在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;
以下是查询计划:
为什么第三个查询这么慢?我可以做些什么来改进它,还是需要拆分查询?
答案 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的最新累积更新包后问题应该消失。