我们有一个存储过程,用于允许用户在包含2000万条记录和40列宽的表中进行搜索。他们可以搜索大约20个不同的列(任意组合),所有这些列都在WHERE
子句中。
此外,每个列都会检查Null,并且只需要搜索部分数据。
这是一个例子
(
@FirstName IS NULL
OR (RTRIM(UPPER(FirstName)) LIKE RTRIM(UPPER(@FirstName)) + '%')
)
AND (@LastName IS NULL)
重写此存储过程的最佳方法是什么?我应该将此存储过程分解为多个小存储过程吗?如果是这样的话?我需要允许用户搜索
当我查看执行计划时,无论传递什么列,它总是进行索引扫描
答案 0 :(得分:1)
要使用动态SQL路由,请使用以下内容:
CREATE PROCEDURE dbo.SearchSomeTable
@FirstName VARCHAR(20),
@LastName VARCHAR(20),
@AnotherCol INT
AS
BEGIN
DECLARE @SQL NVARCHAR(MAX) = N'SELECT SomeColumn FROM SomeTable WHERE 1 = 1',
@ParamDefinition NVARCHAR(MAX) = N'@FirstName VARCHAR(20),
@LastName VARCHAR(20),
@AnotherCol INT';
IF @FirstName IS NOT NULL
@SQL = @SQL + ' AND FirstName = @FirstName';
IF @LastName IS NOT NULL
@SQL = @SQL + ' AND LastName = @LastName';
IF @AnotherCol IS NOT NULL
@SQL = @SQL + ' AND AnotherCol = @AnotherCol';
EXECUTE sp_executesql @sql, @ParamDefinition, @FirstName, @LastName, @AnotherCol;
END
否则,您需要使用OPTION (RECOMPILE)
query hint强制查询在每次运行时重新编译,以获得您传递的特定参数的最佳计划。
答案 1 :(得分:1)
sql语句的select子句是静态的,但from子句和where子句基于参数。
CREATE PROCEDURE dbo.DynamicSearch
@FirstName VARCHAR(20),
@LastName VARCHAR(20),
@CompanyName VARCHAR(50)
AS
BEGIN
DECLARE @SQL NVARCHAR(MAX) = N''
DECLARE @Select NVARCHAR(MAX) = N'SELECT ColA, ColB, ColC, ColD '
DECLARE @From NVARCHAR(MAX) = N'From Person'
DECLARE @Where NVARCHAR(MAX) = N''
IF @FirstName IS NOT NULL
Begin
Set @Where = @Where + 'FirstName = ''' + @FirstName + ''''
End
IF @LastName IS NOT NULL
Begin
if len(@Where) > 0
Begin
Set @Where = @Where + ' AND '
End
Set @Where = @Where + 'LastName = ''' + @LastName + ''''
End
IF @CompanyName IS NOT NULL
Begin
if len(@Where) > 0
Begin
Set @Where = @Where + ' AND '
End
Set @From = @From + ' inner join Company on person.companyid = company.companyid '
Set @Where = @Where + 'company.CompanyName = ''' + @CompanyName + ''''
End
Set @SQL = @Select + @From + @Where
EXECUTE sp_executesql @sql
END
答案 2 :(得分:0)
另一种可能性,尽管以上可能是最合乎逻辑的,是创建一个或多个“搜索”条件表,您在其中插入用户选择,然后对搜索条件执行LEFT JOINS。对于存在等效性且最好是小数据类型(如int)的情况,您只能这样做。对于字符串比较,就性能而言,这种类型的连接可能是可怕的。上述建议(dynamic-sql)的唯一问题是计划缓存膨胀的可能性,因为每次执行只与现有计划存在一个差异,将导致生成新计划。