带有参数的SQL LIKE:巨大的性能命中

时间:2013-10-25 10:25:51

标签: sql-server performance tsql sql-server-2008-r2

我有这个问题:

select top 100 id, email, amount from view_orders
    where email LIKE '%test%' order by created_at desc

运行不到一秒钟。

现在我想参数化它:

declare @m nvarchar(200)
set @m = '%test%'
SELECT TOP 100 id, email, amount FROM view_orders
    WHERE email LIKE @m ORDER BY created_at DESC

5分钟后,它仍在运行。对参数进行任何其他类型的测试(如果我将“like”替换为“=”),则会降低到第一个查询级别的性能。

我使用的是SQL Server 2008 R2。

我试过OPTION(RECOMPILE),它下降到6秒,但它仍然慢得多(非参数化查询是瞬时的)。因为这是我期望经常运行的查询,所以这是一个问题。

表的列是索引的,但视图不是,我不知道它是否会有所作为。

视图连接5个表:一个有3,154,333行(用户),一个有1,536,111行(订单),3个最多有几十行(订单类型等)。搜索在“用户”表(3M行)上完成。

硬编码值
Execution plan using hard-coded values

参数:
Execution plan using parameters

更新

我已使用SET STATISTICS IO ON运行查询。结果如下(对不起,我不知道如何阅读):

硬编码值:

  

表'货币'。扫描计数1,逻辑读取201。

     

表'order_status'。扫描计数0,逻辑读取200。

     

表'付款'。扫描计数1,逻辑读取100。

     

表'礼物'。扫描计数202,逻辑读取404。

     

表'订单'。扫描计数95,逻辑读取683。

     

表'用户'。扫描计数1,逻辑读取7956。

参数:

  

表'货币'。扫描计数1,逻辑读取201。

     

表'order_status'。扫描计数1,逻辑读取201。

     

表'付款'。扫描计数1,逻辑读取100。

     

表'礼物'。扫描计数202,逻辑读取404。

     

表'用户'。扫描计数0,逻辑读取4353067。

     

表'订单'。扫描计数1,逻辑读取4357031。

更新2

此后我看到了“强制索引使用”提示:

SELECT TOP 100 id, email, amount
FROM view_orders with (nolock, index=ix_email)
WHERE email LIKE @m
ORDER BY created_at DESC

不确定它会起作用,我不再在这个地方工作了。

5 个答案:

答案 0 :(得分:3)

这可能是一个参数嗅探问题。 更好的索引或全文搜索是可行的方法,但您可能能够获得可行的妥协。 尝试:

SELECT TOP 100 A, B, C FROM myview WHERE A LIKE '%' + @a + '%'
OPTION (OPTIMIZE FOR (@a = 'testvalue'));

(就像Sean Coetzee建议的那样,我不会在参数中传递通配符)

答案 1 :(得分:0)

向A列添加索引时,您将获胜。 有时索引建议可以由SQL Server管理工作室借用。粘贴查询并按“显示估计执行计划”按钮

答案 2 :(得分:0)

CREATE INDEX index_name ON myview (A);
CREATE INDEX index_name ON myview (B);
CREATE INDEX index_name ON myview (C);

declare @a nvarchar(200)
set @a = '%testvalue%'
SELECT TOP 100 A, B, C FROM myview WHERE A LIKE @a

答案 3 :(得分:0)

如果你尝试会发生什么:

set @a = 'test'
select top 100 A, B, C 
  from myview 
 where A like '%' + @a + '%'

我已尝试对某些虚拟数据进行测试,看起来可能更快。

答案 4 :(得分:0)

参数化版本的估计执行计划显然不正确。我不相信我已经看过两次100%估计费用的查询!因为成本应该总计100%。同样有趣的是,当你明显过滤用户桌上的某些东西时,它认为它需要从订单开始。

我将重建您在视图中引用的所有表的统计信息。

update statistics <tablename> with resample

为每个参与的表做其中一个。

您可以尝试直接运行sql(将粘贴视图主体复制到sql中)并参数化,而不是查看sql是否存在问题。

在一天结束时,即使你修好了它,它实际上只是一个止损距离。您有300万用户,每次运行查询时,sql必须通过所有300万条记录(在您的热门查询中进行75%扫描)才能找到所有可能的记录。获得的用户越多,查询得到的速度就越慢。非全文索引不能用于前面带有通配符的类似查询。

在这种情况下,您可以将sql索引视为书籍索引。您可以使用带有“部分”单词的书籍索引来快速找到任何内容吗?不,你必须扫描整个索引以找出所有可能性。

您应该在视图中考虑全文索引。