SQLServer数据库性能优化,多条件、LEFT JOIN及分页查询优化
多条件查询及 left join 的利用,几乎在所有项目都会用到。但只有数据量大、并发大时才会有人去注意他的性能。
先来看一个最有代表性的分页存储过程:
ALTER PROCEDURE [dbo].[P_Article_List]
@page int=1,
@pagesize int=10,
@key VARCHAR(450)=''
AS
BEGIN
SELECT COUNT(1)OVER(PARTITION BY '''') AS Total,b.NickName,b.Avator,a.*
FROM dbo.t_article a with (NOLOCK)
LEFT join t_user b with (NOLOCK) ON b.UserID=a.UserID
WHERE a.IsValid=1
AND (@key='' or a.Title like '%'+@key+'%')
ORDER BY a.order DESC desc
OFFSET @pagesize*(@page-1) ROWS FETCH NEXT @pagesize ROWS ONLY
END
这是一个很标准的存储过程,这样写代码也很漂亮,但这样的性能很差。通过查看执行计划,你会发现一个很奇怪的问题:
明明是 left join,为什么执行计划里是 inner join 呢,要知道后者的性能是低很多的。
这个问题是因为 where 条件导致的,所以我们要优化它,就必须用新的方式:
先把左边表的数据按条件查询出来放入临时表,再将临时表与右表 left join,不带where
当然,还有一个很重要的因素,分页,我们可以把分页也在临时表里先做了,比如一页10条,这样最后 left join时,左表只有10条数据,这个性能,就会很高
最后贴出优化后的存储过程:
ALTER PROCEDURE [dbo].[P_Article_List]
@page int=1,
@pagesize int=10,
@key VARCHAR(450)=''
AS
BEGIN
SELECT COUNT(1)OVER(PARTITION BY '''') AS Total,b.NickName,b.Avator,a.* FROM
(SELECT * FROM dbo.t_article with (NOLOCK)
WHERE IsValid=1
AND (@key='' or Title like '%'+@key+'%')
ORDER BY order DESC desc
OFFSET @pagesize*(@page-1) ROWS FETCH NEXT @pagesize ROWS ONLY
) a
LEFT join t_user b with (NOLOCK) ON b.UserID=a.UserID
END
搞定,最后测试,我们数据库的这个存储过程,查询时间从平均 2.3 秒优化到了 0.15 秒!