我有一个存储过程,使用全文索引搜索产品(250,000行)。
存储过程采用的参数是全文搜索条件。这个参数可以为null,所以我添加了一个空检查,并且查询突然开始运行速度慢了几个数量级。
-- This is normally a parameter of my stored proc
DECLARE @Filter VARCHAR(100)
SET @Filter = 'FORMSOF(INFLECTIONAL, robe)'
-- #1 - Runs < 1 sec
SELECT TOP 100 ID FROM dbo.Products
WHERE CONTAINS(Name, @Filter)
-- #2 - Runs in 18 secs
SELECT TOP 100 ID FROM dbo.Products
WHERE @Filter IS NULL OR CONTAINS(Name, @Filter)
以下是执行计划:
查询#1
查询#2
我必须承认我对执行计划不太熟悉。对我来说唯一明显的区别是连接是不同的。我会尝试添加一个提示,但在我的查询中没有加入我不知道该怎么做。
我也不太明白为什么使用名为IX_SectionID的索引,因为它是一个只包含列SectionID的索引,并且该列不在任何地方使用。
答案 0 :(得分:8)
OR
可以粉碎表现,所以这样做:
DECLARE @Filter VARCHAR(100)
SET @Filter = 'FORMSOF(INFLECTIONAL, robe)'
IF @Filter IS NOT NULL
BEGIN
SELECT TOP 100 ID FROM dbo.Products
WHERE CONTAINS(Name, @Filter)
END
ELSE
BEGIN
SELECT TOP 100 ID FROM dbo.Products
END
请看这篇文章:Dynamic Search Conditions in T-SQL by Erland Sommarskog和这个问题:SQL Server 2008 - Conditional Query。
答案 1 :(得分:3)
第一个查询计划看起来很简单:
CONTAINS(Name, @Filter)
concatenation operator形成两个记录集的并集。所以看起来第二个查询正在做:
@Filter
的任何其他值。如果正确,则常量扫描会解析@Filter is not null
。CONTAINS(Name, @Filter)
散列连接以内存换取速度;如果你的系统有足够的内存,它比循环连接快得多。这很容易解释10-100倍的减速。
一种解决方法是使用两个不同的查询:
if @Filter is null
SELECT TOP 100 ID FROM dbo.Products
else
SELECT TOP 100 ID FROM dbo.Products WHERE CONTAINS(Name, @Filter)
答案 2 :(得分:1)
您已经引入了OR条件。 在大多数情况下,明确检查NULL并对您的方法执行一次查询要快得多。
例如试试这个:
IF @Filter IS NULL
BEGIN
SELECT TOP 100 ID FROM dbo.Products
END
ELSE
BEGIN
SELECT TOP 100 ID FROM dbo.Products
WHERE @Filter CONTAINS(Name, @Filter)
END