我有这样的查询:
select top(10) * from dbo.myTable where DisplayName like 'farm%'
这会导致对DisplayName进行索引搜索,因为通配符正在跟踪。但是当我这样做时情况并非如此:
declare @val varchar(200) = 'farm'
select top(10) * from dbo.myTable where DisplayName like @val + '%'
或者这个:
declare @val varchar(200) = 'farm%'
select top(10) * from dbo.myTable where DisplayName like @val
在这些情况下,SQL会依赖于速度慢得多的索引扫描操作。找到的值是一个在运行时提供的参数,所以显然我不能只为我的目的使用第一个查询。
我有什么办法可以:
我意识到通配符的存在与否会影响执行计划,但SQL似乎并不理解通配符总是被使用,即使你将它连接到值,就像在查询#2中一样。
答案 0 :(得分:3)
SQL Server can use a range seek for these queries(如果变量包含一个前导通配符,则该范围最终会成为整个索引。)
如果在这种情况下不选择这样做,很可能是因为使用变量意味着它不能准确估计选择性。您可以尝试添加OPTION (RECOMPILE)
提示,以便考虑实际的变量值。
答案 1 :(得分:1)
我认为Martin是正确的,因为当我用主键和DisplayName列替换select *时,SQL实际上做了索引搜索,从而消除了键查找。
此外,LIKE'farm%'正在实现为DisplayName> ='farm'AND DisplayName< 'farN',所以我决定完全放弃LIKE算子。
select top(10) * from dbo.EPFSuppliers with(forceseek)
where DisplayName >= @str and DisplayName < left(@str,len(@str)-1) + char(ascii(right(@str,1)) + 1)
forceseek提示是必要的,因为SQL估计在729匹配的行数,这在我的情况下是完全不切实际的数字。
我相信这种方法优于使用通配符,通配符需要预处理字符串以删除转义字符。