前言
在实际开发过程中,当数据量比较多的时候,大量的数据一下子展示到页面上是非常不可取的。所以我们通常要进行分页(这里的分页是指真分页),而不是前端JS实现的假分页。
最近的学习过程中,使用ASP.NET MVC配合Layui框架进行开发时,根据Layui Page传回的参数要进行分页操作(虽然EntityFramework提供了非常便捷的分页方法,但是SQL什么时候都不能忘掉吧O(∩_∩)O哈哈~)。索性对于分页SQL这一块,自己做一个系统的总结。
本篇博客针对于SQL Server数据库进行讨论
一、三种分页SQL语句的介绍和写法
示例数据库的字段:
假设有100条数据,每页显示10条,我们取第3页数据来说
这里按照三种SQL的的破壳日从古到今进行介绍叭!
1.top+嵌套查询
介绍:简单的来说就是,我们需要第21-30条数据,我们先查前20条id为一个集合,再从原表中取id不在这个集合中的前十条;
写法:
select top 10 * from BigDataTable where id not in(select top 20 id from BigDataTable order by id) order by id
注:
两个排序字段要保持一致!
2.ROW_NUMBER()开窗函数(支持SqlServer 2005版本以上)
介绍:通过ROW_NUMBER()生成序号列,根据序号列取需要数据
写法:我一般建立一个视图(#^.^#)
create view View_Page
as
select *,ROW_NUMBER()over(order by id) as rowindex from BigDataTable
SELECT * FROM View_Page WHERE rowindex>=21 AND rowindex<=30
3.offset fetch(SqlServer 2012 版本以上)
介绍:offset x rows=>跳过前x行 fetch next y rows=>取之后的y行
写法:
SELECT * FROM BigDataTable ORDER BY id OFFSET 20 ROWS FETCH NEXT 10 ROWS ONLY
注意:一定要排序吖!
二、对比
本部分,我们用了一个含有1028135条数据的数据库。
分别使用上述三种SQL来取得1000001-1000020条数据来进行对比。
数据如下:
1.使用top+嵌套查询执行结果如下:
取十次查询时间求平均值:(1.023+0.988+0.949+0.960+1.028+1.002+0.957+0.956+0.961+0.964)/10 =0.9788s
2.使用ROW_NUMBER()开窗函数执行结果如下:
取十次查询时间求平均值:(0.839+0.841+0.845+0.840+0.853+0.845+0.828+0.861+0.874+0.861)/ 10=0.8487s
3.offset fetch执行结果如下:
取十次查询时间求平均值:(0.356+0.358+0.322+0.322+0.350+0.325+0.355+0.315+0.328+0.330)/ 10=0.3361s
注:这里进行的对比这是大概结论呢,因为我们没有排除以主键,聚集索引作为排序字段带来的影响。
从上可以大致得出,效率:top+嵌套查询<ROW_NUMBER()<offset fetch
从我前面说的它们的破壳日来看,时代在不断进步,微软的工程师们也在不断进步提升O(∩_∩)O哈哈~
三、在ASP.NET下的简要说明
上面我们直接拿了具体的SQL语句来进行说明,这样更直观便于理解,实际上我们在开发过程中不考虑框架自带的方法,一般需要写成存储过程,后台传入相应参数进行调用。
1.在ASP.NET WebForm下
ASP.NET WebForm项目中,我们常常采用三层架构模式进行开发。
那么我们若想实现分页效果(不考虑ASP.NET WebForm Pager控件,以及GridView自带的分页效果),我们一般需要在DAL层中通过SQLHelper使用ADO.NET调用封装以上SQL语句的存储过程拿到分页后的数据,后台将分页后的数据展示给前台。
2.在ASP.NET MVC下
ASP.NET MVC项目中,我们通常会使用EntityFramework放入Model层中操作数据。
EntityFramework中提供了两个分页的方法,Skip()、Take(),使用这两个方法前要进行OrderBy()操作。当时堂课上学习的时候我就猜测,这一定是在数据库中执行了分页SQL的一种。
通过SqlServer Profiler对数据库跟踪,调用Skip()、Take()结束延迟加载之后,数据库中执行了offset fetch分页语句
注:不是一定就是执行offset fetch分页SQL!
在我的环境VisualStudio 2017+SqlServer 2014下 执行的是offset fetch分页语句
在VisualStudio 2013+SqlServer 2008R2下 执行的是ROW_NUMBER()分页语句
四、结语
以上就是我在大学期间,了解和掌握的SqlServer下的三种分页语句的使用、看法以及在.NET下的应用和一些见解,并且在百万数据下的简单的效率对比。
花了近两个小时去写这个文章,是自己对这块知识做得一个笔记也是对分页SQL做了一个系统性的总结。虽然现在分页组件(MvcPager等),简单引入DLL,传入几个参数便可实现很好的分页效果。但是,我觉得我们知道怎么去用,也需要了解究竟是怎么一回事。作为一个学生,这些基本功夫还是需要扎实、牢固,技术才能不断得到提升!
这些都是在课堂上以及平时开发过程中,自己的认识。可能不够严谨和准确,需要详细了解可以阅读微软官方文档进一步学习!