为什么这两个查询的性能如此不同?
我有一个使用全文索引搜索产品(250,000 行)的存储过程。
存储过程采用一个参数,即全文搜索条件。该参数可以为空,因此我添加了空检查,查询突然开始运行速度减慢了几个数量级。
-- 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 的索引,并且该列在任何地方都没有使用。
I have a stored proc that searches for products (250,000 rows) using a full text index.
The stored proc takes a parameter that is the full text search condition. This parameter can be null, so I added a null check and the query suddenly started running orders of magnitude slower.
-- 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)
Here are the execution plans:
Query #1
Query #2
I must admit that I am not very familiar with execution plans. The only obvious difference to me is that the joins are different. I would try adding a hint but having no join in my query I am not sure how to do that.
I also do not quite understand why the index called IX_SectionID is used, since it is an index that only contains the column SectionID and that column is not used anywhere.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
OR
会降低性能,所以这样做:看看这篇文章:Erland Sommarskog 的 T-SQL 中的动态搜索条件 和这个问题:SQL Server 2008 -条件查询。
OR
can crush performance, so do it this way:Look at this article: Dynamic Search Conditions in T-SQL by Erland Sommarskog and this question: SQL Server 2008 - Conditional Query.
第一个查询计划看起来很简单:
CONTAINS(Name, @Filter)
连接运算符形成两个记录集的并集。所以看起来第二个查询正在执行:
@Filter
的任何其他值。如果正确,持续扫描将解析@Filter is not null
。CONTAINS(Name, @Filter)
的全文搜索哈希连接会消耗内存为了速度;如果您的系统有足够的内存,它比循环连接快得多。这可以轻松解释 10-100 倍的减速。
一种修复方法是使用两个不同的查询:
The first query plan looks straightforward:
CONTAINS(Name, @Filter)
The concatenation operator forms a union of two recordsets. So it looks like the second query is doing:
@Filter
. If correct, the constant scan resolves@Filter is not null
.CONTAINS(Name, @Filter)
A hash join trades memory for speed; if your system has enough memory, it's much faster than a loop join. This can easily explan a 10-100x slowdown.
One fix is to use two distinct queries:
您引入了 OR 条件。
在大多数情况下,与您的方法相比,显式检查 NULL 并执行一个查询要快得多。
例如尝试这个:
You've introduced an OR condition.
In most cases it is simply much faster to check explicitly for NULL and perform one query vs your method.
For instance try this: