微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

sqlserver中使用row_number进行分页,效率很高!速度很快!

                  最近,童鞋要做一个分页,数据量很大,几十万条数据,更坑爹的是,还是要经过表连接进行查询,速度慢得像乌龟!!

                  

                 怎么进行优化,可以让逻辑更清晰,效率更高呢?我试探的过程大概分为以下几个步骤:

              1.首先因为要进行多张表连接,所以在数据库中先做了一个视图,把表连接起来。(但是这样查询速度和直接在sql语句中写表连接差不多,但是如果把表连接写在视图中,程序中的sql语句将变得简洁,思路更清晰)

建立视图的sql语句如下:视图名为searchJCR

SELECT     dbo.JCR_Table.JournalID,dbo.JCR_Table.JournalFullTitle,dbo.JCR_Table.JournalISOTitle,dbo.JCR_Table.JournalJCRTitle,dbo.JCR_Table.JournalISSN,dbo.JCR_Table.JournalLanguage,dbo.JCR_Table.JournalUpdateYear,dbo.SubjectCategories.TotalJouranls,dbo.SubjectCategories.JournalRank,dbo.SubjectCategories.JournalQuartile,dbo.JCRCategory_Table.CategoriesEName,dbo.JCRCategory_Table.CategoriesCName,dbo.JCRIF_Table.YearNum,dbo.JCRIF_Table.IFscore,dbo.JCRCategory_Table.CategoriesID
FROM         dbo.JCR_Table INNER JOIN
                      dbo.JCRIF_Table ON dbo.JCR_Table.JournalID = dbo.JCRIF_Table.JournalID INNER JOIN
                      dbo.SubjectCategories ON dbo.JCR_Table.JournalID = dbo.SubjectCategories.JournalID AND 
                      dbo.SubjectCategories.YearNum = dbo.JCRIF_Table.YearNum INNER JOIN
                      dbo.JCRCategory_Table ON dbo.SubjectCategories.CategoriesID = dbo.JCRCategory_Table.CategoriesID
                            2.然后再程序中使用传统方法进行分页
这时候出现了一个问题,使用的视图查询出来的结果又很多JournalID重复的记录,这样使用JournalID进行分页就不可行了。所以需要做的就是为每一条查询记录指定唯一一个标识,在oracle中有伪列rowid,可以用于区分每一条记录,在sql server2005之前,没有办法区分,但是在sql2005之后,提供了一个ROW_NUMBER() OVER(PARTITION BY COLUMN ORDER BY COLUMN)函数用于实现类似于伪列的效果

                        3.然后在程序中使用row_number()over()进行分页。语句如下

select top 20 * from (select row_number()over(order by YearNum DESC,JournalID ASC) as rowid,sJCR.* from searchJCR as sJCR)where rowid not in(select top 20*queryPage  rowid from (select row_number()over(order by YearNum DESC,sJCR1.* from searchJCR as sJCR1) where 1=1 and ...) and 1=1 and... order by YearNumDESC,JournalID ASC

查询速度很慢。后来做了优化(CTE,关于CTE的介绍将读者参阅《SQL Server2005杂谈(1):使用公用表表达式(CTE)简化嵌套SQL》),优化后的代码如下:

with t_rowtable  
as
(
    select row_number()over(order by YearNum DESC,JournalID ASC) as row_number,* from [JournalDB].[dbo].[searchJCR] where 1=1

)
select * from t_rowtable where row_number>100
 and row_number <= 60000

row_number函数的用途是非常广泛,这个函数功能是为查询出来的每一行记录生成一个序号生成的机制是,按over(排序条件)中的排序条件对每条记录顺序生成一个rowid,然后将记录按select的order by顺序显示出来。其中“where row_number>100
 and row_number <= 60000
” 可以用来控制每页的显示的记录,可以用来分页,“where row_number>(page-1)*pageSize
 and row_number <= page*pageSize
”,并且只需要将筛选记录的条件拼接在where 1=1之后,这样即使上十几万的数据都可以在3s中之内查询出来,效率很高。例如:

row_number列是由row_number函数生成的序号列。在使用row_number函数是要使用over子句选择对某一列进行排序,然后才能生成序号。

    实际上,row_number函数生成序号的基本原理是先使用over子句中的排序语句对记录进行排序,然后按着这个顺序生成序号。over子句中的order by子句与sql语句中的order by子句没有任何关系,这两处的order by 可以完全不同,如下面的sql语句所示:

 

select  row_number()  over ( order  by field2 descas row_number,* from t_table order by field1 desc

 

    上面的sql语句的查询结果如图所示。


另外要注意的是,如果将row_number函数用于分页处理,over子句中的order by 与排序记录的order by 应相同,否则生成的序号可能不是有续的。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐