4

我有这个查询:

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 行)上完成的。

硬编码值:
使用硬编码值的执行计划

参数 :
使用参数的执行计划

更新

我已经使用SET STATISTICS IO ON. 这是结果(对不起,我不知道如何阅读):

硬编码值:

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

表“订单状态”。扫描计数 0,逻辑读取 200。

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

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

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

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

参数 :

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

表“订单状态”。扫描计数 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

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

4

5 回答 5

3

这可能是参数嗅探问题。更好的索引或全文搜索是可行的方法,但您可能可以获得可行的折衷方案。尝试:

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

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

于 2013-10-25T10:57:38.833 回答
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
于 2013-10-25T10:34:28.493 回答
0

当您向 A 列添加索引时,您肯定会赢。有时索引建议可以由 SQL Server 管理工作室借用。粘贴您的查询并按显示估计的执行计划按钮

于 2013-10-25T10:31:04.410 回答
0

参数化版本的估计执行计划显然是不对的。我不相信我见过两次估计成本为 100% 的查询!因为成本应该是100%。有趣的是,当您清楚地按用户表上的某些内容进行过滤时,它认为它需要从订单开始。

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

update statistics <tablename> with resample

对涉及的每个表执行其中一项。

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

归根结底,即使您解决了这个问题,这实际上也只是一个权宜之计。您有 300 万用户,每次运行查询 sql 都必须遍历所有 300 万条记录(顶部查询中的 75% 扫描)才能找到所有可能的记录。您获得的用户越多,查询速度就越慢。非全文索引不能用于前面带有通配符的类似查询。

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

您应该真正考虑在您的视图中使用全文索引。

于 2013-10-26T04:49:06.770 回答
0

如果您尝试:

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

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

于 2013-10-25T10:47:19.147 回答