我有一个我正在继承并尝试优化的搜索查询。我很想知道是否有人有这方面的最佳做法和建议。生产服务器仍然是SQL Server 2000。
查询是一种高级客户搜索存储过程,它接受5个不同的搜索条件参数(即名字,姓氏,地址,电话等)来搜索数百万个记录表。 WHERE子句中的所有连接列和列都有索引。此外,初始查询将记录转储到用于分页容量的表变量中。
INSERT INTO @tempCustTable (CustomerID, FirstName, LastName, City, StateProvince, Zip, PhoneNumber)
SELECT DISTINCT cu.CustomerID, cu.FirstName, cu.LastName, a.City,
a.StateProvince, a.Zip, p.PhoneNumber
FROM Customer cu WITH(NOLOCK)
LEFT OUTER JOIN Address a WITH(NOLOCK) ON cu.CustomerID = a.CustomerID
LEFT OUTER JOIN Phone p WITH(NOLOCK) ON cu.CustomerID = p.CustomerID
WHERE (cu.LastName = @LastName OR cu.LastName LIKE @LastName + '%')
AND (@FirstName IS NULL OR cu.FirstName = @FirstName OR cu.FirstName LIKE @FirstName + '%')
AND (@StateProvince = '' OR a.StateProvince LIKE @StateProvince)
AND (@City = '' OR a.City LIKE @City + '%')
AND (@Zip = '' OR a.Zip = @Zip OR a.Zip LIKE @Zip + '%')
ORDER BY cu.LastName, cu.FirstName
有没有人对如何提高查询效果有任何建议?
答案 0 :(得分:2)
不是这整行
AND (@Zip = '' OR a.Zip = @Zip OR a.Zip LIKE @Zip + '%')
与此相同
AND (a.Zip LIKE @Zip + '%')
肯定
AND (a.Zip LIKE @Zip + '%')
与
相同a.Zip = @Zip OR a.Zip LIKE @Zip + '%'
答案 1 :(得分:1)
您可以清理代码中的大量冗余,正如SQLMenace所指出的那样。
另一件事是,ORDER BY不应该与INSERT..SELECT一起使用。在这种情况下,ORDER BY毫无意义。人们偶尔使用它来强制IDENTITY列以某种方式运行,但这是一个坏习惯IMO。
我不知道这对你的情况是否有帮助,但我最近遇到的一件事是在存储过程中SQL Server(我使用的是2005,但2000年可能也是如此)不会短 - 在许多情况下,电路是OR条件。例如,当您使用:
时@my_parameter IS NULL OR my_column = @my_parameter
即使为@my_parameter传入NULL值,它仍将评估后半部分。即使我将存储过程设置为重新编译(和SELECT),也会发生这种情况。诀窍是通过使用CASE语句强制短路。使用该技巧(并删除一些冗余),您的语句将如下所示:
INSERT INTO @tempCustTable
(
CustomerID,
FirstName,
LastName,
City,
StateProvince,
Zip,
PhoneNumber
)
SELECT DISTINCT
cu.CustomerID,
cu.FirstName,
cu.LastName,
a.City,
a.StateProvince,
a.Zip,
p.PhoneNumber
FROM Customer cu WITH(NOLOCK)
LEFT OUTER JOIN Address a WITH(NOLOCK) ON cu.CustomerID = a.CustomerID
LEFT OUTER JOIN Phone p WITH(NOLOCK) ON cu.CustomerID = p.CustomerID
WHERE
(cu.LastName LIKE @LastName + '%') AND
(1 =
CASE
WHEN @FirstName IS NULL THEN 1
WHEN cu.FirstName LIKE @FirstName + '%' THEN 1
ELSE 0
END
) AND
(1 =
CASE
WHEN @StateProvince = '' THEN 1
WHEN a.StateProvince = @StateProvince THEN 1
ELSE 0
END
) AND
(1 = CASE
WHEN @City = '' THEN 1
WHEN a.City LIKE @City + '%' THEN 1
ELSE 0
END
) AND
(1 = CASE
WHEN @Zip = '' THEN 1
WHEN a.Zip LIKE @Zip + '%' THEN 1
ELSE 0
END
)
它使查询更长,可能更复杂一些,但为了获得更好的性能,它可能是值得的。如果您的标准包含可能会被短路的子查询,则特别为真。
最后...... 与您的参数保持一致。对于@FirstName,您检查NULL值以确定它是否已被使用,但对于其他正在检查空字符串的值。这里基本编码101你需要注意。
答案 2 :(得分:0)
答案 3 :(得分:0)
我会尝试不让我的sql代码添加'%',而是希望参数已经拥有它,当然,这是在你的应用程序中验证它之后!然后不要包含'='比较,一直使用LIKE:
WHERE(cu.LastName LIKE @LastName)
而不是:
WHERE(cu.LastName = @LastName OR cu.LastName LIKE @LastName +'%')
答案 4 :(得分:0)
您可以使用动态sql构建查询。这将消除大多数OR,也意味着您只需要在WHERE语句行中包含用户实际输入的参数。
如果这样做,请确保使用sp_executesql而不是exec,以便可以参数化动态sql,以便可以缓存查询计划。