【测试】两种数据库,四种分页算法的效率比较

 

分页算法本身没有什么快慢之分,对反应速度起到决定作用的是——能否有效地利用索引!

 

算法 评价 缺点 适用的数据库
max 效率最高的 只能有一个排序字段 Excel、Access、SQL Server 2000(2005)
颠倒Top 适用范围最广的 最后一页多数据 Excel、Access、SQL Server 2000(2005)
表变量 最大失所望的 太多了 SQL Server 2000(2005)
Row_Number 只适合SQL Server2005 只能用在一种数据库 SQL Server 2005

一、max


     缺点就是只能有一个排序字段,而且排序字段的值不能有重复值,或者说可以有重复值,但是不能在一页的最上面、最后重复。优点就是很容易设置索引,按那个字段排序就把那个字段设置上索引就可以了,设置索引后,分页速度会大大提高,记录越多越明显,因为利用了索引。索引的作用是什么?简单地说就是,先站排,再找个头最高的。假设说要找到一个班级里面个头最高的,那要怎么办呢,先让同学按照大小个站排,然后谁是最高的就一目了然了。设置好了索引就相当于已经排好了队,剩下的就快多了。

 

二、颠倒Top 

 

     这个是颠颠倒倒的一种优化,必须有一个主键,且不能是复合主键。由于大部分情况都比较好设置索引,也可以利用索引,所以分页效果也是可以的。

 

三、表变量

     由于一直在使用颠倒top法和定位法,所以一直对表变量不感冒,由于是吴旗娃的分页控件推荐的一种算法,这次升级的时候还是去研究了一下。仔细看了一下,缺点还真是多。由于表变量的思路是,要把主键和自增字段放在表变量里面,然后利用自增字段来分页。就像上面的例子,要先站排,然后报数,然后根据报数来提取数据。这样就带来了很多的缺点:

     1、表必须有一个主键,且不能是复合主键。复合主键的话,就不好提取数据了。
     2、主键的类型会影响分页算法的编写。int的和datetime的,在定义表变量的时候字段类型是不一样的。
     3、如果只按照主键排序的话,那么主键的索引就完全被浪费掉了。原先已经排好队了,却又让她们重新排一遍。
     4、越往后翻页,需要往表变量里存放的数据也就越多,放的多倒无所谓,其他的算法也会放一些数据到“临时表”里面,但是问题在于,自增字段没有索引,加的数据越多速度也就自然越慢。
     5、只能在SQL Server 2000和SQL Server2005里面使用,而且在2005里面速度明显没有Row_Number快,吴旗娃的那个网站推荐的分页算法,都分成了两个版本,SQL2000的和SQL2005的,对于后者推荐使用Row_Number。

 

     说了这么多的缺点,不会一点优点都没有吧,有点恐怕就是编写起来比较容易吧,便于理解。颠倒Top就不好理解。所以说这个是最大失所望的分页算法。

四、Row_Number

     这个我只会用,内部原理也不太理解,大多数情况效率也还行,但是有一次发现他不能利用索引,郁闷。

     光说不练,恐怕大家也不太相信,尤其说了表变量那么的坏话,那么下面就用测试来证明一下,看看各个分页算法的表现。要说测试也真麻烦,数据库至少就有三个,分页算法有四个,数据上呢又有单字段排序、多字段排序,单表分页、多变关联分页,少量数据和海量数据,能否利索引。

3*4*2*2*2*2 = 192 。这么多是不是有点晕,先简化一下吧,这里先用SQL Server2000 测试一下单表海量数据的情况。

三种分页算法、单表、海量数据(二百万吧,少了对比不出来效果)。

 

 

先介绍一下测试环境

 

数据库: SQL Server2000

IDE:VS2008。

CPU:AMD3000+

内存:DDR2 1G

硬盘:串口160G

 

三种分页算法:Max、表变量、颠倒top。

 

     我们使用Northwind数据库,Products表进行测试,自带的数据不够,我们来复制点数据吧,用insert into select 的方式,添加2523136条记录,一页显示15条记录,一共有168210页 。那么我们就记录一下第一次加载、前几页、前100页、第1000页、第10000页、最后几页和最后一页的用时和内存占用情况。

 

这是单字段排序的测试结果,按照  ProductID  排序。
单位:毫秒。 

分页算法 第一次 前几页 前100页 1000页 10000页 100000页 最后几页 最后一页
MaxMin 953/40M 400/40M 0-15/50M 0-15/50M 78-93/68M 3.62s/210M
765/210M
2.80s/310M
1.28s/310M
5.62s/310M
1.28s/310M
颠倒Top 875/40M 400/40M 0-15/50M 15-31/50M 281/69M
93-125/69M
2.96s/210M
1.3s/210M
3.78s/310M
1.7s/310M
15(特殊处理)
表变量 968 468 0-15/50M 11.18s/55M
93-109/59M
24.265s/76M
859/77M
超时了
45.171s/230M
11.78s/240M
8.281s
这个就不测试了 这个就不测试了

 

     记录说明:

     1、如果一个格里面有两个时间,那么前面的表示大范围跳页(比如从100页跳到1000页)需要的时间,后面是显示下一页需要的时间。

     2、前面的是执行时间,后面的是内存增量。

     3、第一次运行的时候SQL Server需要加载一些数据到内存里面,所以时间比较长。

     4、第一页的时候需要使用Count(*)来统计总记录数,所以时间也有点长。而在访问其他页的时候就不用统计总记录数了,所以时间会很快。

     5、CPU的占用率就不记录了,基本上都占满了,看来AMD3000+有点弱了。

 

第一页的SQL语句:

select top 15 * from Products order by ProductID

 

MaxMin的SQL语句:
select top 15 * from Products where productid>= (SELECT max(productid ) from (select top 526 productid from Products order by productid ) as t ) order by productid

 

颠倒Top的SQL语句:
select * from Products where productid in ( select top 15 productid from ( select top 420 productid from Products order by productid ) as t order by t.productid desc )order by productid

 

对最后一页得分页算法作了特殊处理,目的是去掉bug,并不是为了提高速度。

 

颠倒Top的显示最后一页的SQL语句
select * from ( select top 1 * from Products order by productid desc ) as t order by t.productid

 

表变量的SQL语句:
declare @tt table(id int identity(1,1),nid int) insert into @tt(nid) select top 2130 ProductID from Products order by ProductID select * from Products t1, @tt t2 where t1.ProductID =t2.nid and t2.id between 2116 and 2130

 

还真的是不行,从第一万页跳转到第十万页的时候,很不幸,等待了45.171秒之后超时了,由于数据访问函数库在遇到异常的时候并不抛出异常,所以能够得到运行的时间,通过查看错误日志,得知“超时时间已到。在操作完成之前超时时间已过或服务器未响应。”
再次刷新才得到了数据。

 

在测试的时候表变量的分页时间很不稳定,一会快一会慢的,大范围跳页的时候还总是超时。而颠倒Top就比较稳定。

 

 

这是多字段排序的测试结果,按照   UnitPrice,ProductID desc  排序。设置了索引:UnitPrice,ProductID desc
单位:毫秒。 

分页算法 第一次 前几页 100页 1000页 10000页 100000页 最后几页 最后一页
颠倒Top 375/55M 15-31/57M 15-31/60M 62-78/63M 687/63M
486/64M
5.18s/65M
4.3s/65M
8.15s/66M
7-8s/66M
15(特殊处理)
表变量 968 15-31/58M 1.31/59M
46/60M
12.17s/60M
93-125/60M
真实搞不懂,怎么超时了
27.39s/76M
8-9s/77M
900/77M
超时了
45.171s/100M
10.2s/100M
9.3s
27.2s/100M
9.3s
这个就不测试了

 

 

这是SQL Server 2005 的测试结果,多字段排序,按照   UnitPrice,ProductID desc  排序。设置了索引:UnitPrice,ProductID desc
单位:毫秒。

分页算法 第一次 前几页 100页 1000页 10000页 100000页 最后几页 最后一页
颠倒Top 375/55M 15-46/57M 15-46/100M 78-93/110M 531/117M
466/117M
5-8s/118M 7-10s/120M 15(特殊处理)
表变量 968 31-46/100M 2.62/100M
0.4s 或1.6s/100M
17.34s/110M
93-156/110M

25.57s/76M
1.25s/77M
超时了
22.82s/130M
15.2s/130M
9.3s
27.2s/100M
9.3s
这个就不测试了
Row_Number 500 15/93M 546
15-31
4.82s/200M
93-106/210M
3.15/265M
3.96/263M
 比较慢,总超时,不想测了。    

 

这里增加了Row_Number算法的测试,

 

Row_Number的SQL语句:

with t_pager as (select myIndex = ROW_NUMBER() OVER (ORDER BY UnitPrice,ProductID desc ),* from Products ) select * from t_pager where myIndex between 150031 and 150045

 

 

我都怀疑这个测试结果,如果测试结果没有问题的话,那么就说明“颠倒top”的效率是最高的,而且适用范围也很广。

 

但是我还是比较怀疑这个结果,难道 Row_Number会这么慢?是不是拼接出来的SQL语句有什么问题?或者那个环节出了问题?

 

===============================================================================

 

 测试用的代码

 

先建立一个基类,定义一个GridView、一个QuickPager分页控件和一个标签,然后override OnInit()函数,再添加一个事件就ok了。因为是对同一个表进行分页,所以分页控件的属性设置都是一样的,只是分页算法的属性不同,那么我们就可以把相同的设置放在基类里面,不同的放在具体的页面里。

 

QuickPager 分页控件在基类里面的使用方法

 

public class BaseList : System.Web.UI.Page
    {
        protected JYK.Controls.QuickPager myPager = null;
        protected System.Web.UI.WebControls.GridView GV = null;
        protected Label lbl = null;

        protected DateTime dt1;

        protected override void OnInit(EventArgs e)
        {
            base.OnInit(e);

            //设置分页控件的属性

            myPager.ControlGrid = GV;

            myPager.TableName = "Products";
            myPager.TableShowColumns = "*";
            myPager.TableIDColumns = "ProductID";
            //myPager.TableOrderColumns = "ProductID";ProductName
            myPager.TableOrderColumns = "UnitPrice,ProductID desc";

            myPager.PageSize = 15;

            //添加事件
            myPager.GridBinded += new JYK.Controls.QuickPager.EventPageChange(myPager_GridBinded);

            dt1 = DateTime.Now;
        }

        void myPager_GridBinded(object sender, JYK.Controls.Page.PageArgs e)
        {
            TimeSpan ts = DateTime.Now - dt1;
            lbl.Text = "秒:" + ts.Seconds + ",毫秒:" + ts.Milliseconds;
            lbl.Text += "<BR>" + myPager.GetPagerSQL;
        }

        void myPager_PageChanged(object sender, JYK.Controls.Page.PageArgs e)
        {
           
        }
    }

 

然后建立一个aspx页面,拖拽进来三个控件就可以了

 

Code
<asp:GridView ID="GV" runat="server" Width="100%">
        </asp:GridView>
        <JYK:QuickPager ID="myPager" runat="server"  />
    <asp:Label ID="lbl" runat="server" Text=" "></asp:Label>

 

 

Code
public partial class lst_Max : BaseList
    {
        protected void Page_Load(object sender, EventArgs e)
        {
            if (!Page.IsPostBack )
                myPager.SetSQLKind = JYK.Controls.Page.myPageSQLKind.Row_Number;
        }
    }

 

 

     我们还可以顺便对比一下SQL 2000 和 SQL 2005,好像在这种情况下05并没有太多的优势。Row_Number也没有想象中的那么好,也许是我写的不对,也许四、五个排序字段的时候才能体现出来优势?不过不管怎么说,更换分页算法对于QuickPager来说是很容易的事情,如果发现速度慢了,那么就换成其他的分页算法试一试,再加个索引试一试,呵呵。

 

QuickPager 分页控件 v2.0.0.8的下载地址:

 http://www.cnblogs.com/jyk/archive/2008/07/29/1255891.html

时间: 2024-11-08 22:14:42

【测试】两种数据库,四种分页算法的效率比较的相关文章

详解Android提交数据到服务器的两种方式四种方法_Android

Android应用开发中,会经常要提交数据到服务器和从服务器得到数据,本文主要是给出了利用http协议采用HttpClient方式向服务器提交数据的方法. 代码比较简单,这里不去过多的阐述,直接看代码. /** * @author Dylan * 本类封装了Android中向web服务器提交数据的两种方式四种方法 */ public class SubmitDataByHttpClientAndOrdinaryWay { /** * 使用get请求以普通方式提交数据 * @param map 传

详解Android提交数据到服务器的两种方式四种方法

Android应用开发中,会经常要提交数据到服务器和从服务器得到数据,本文主要是给出了利用http协议采用HttpClient方式向服务器提交数据的方法. 代码比较简单,这里不去过多的阐述,直接看代码. /** * @author Dylan * 本类封装了Android中向web服务器提交数据的两种方式四种方法 */ public class SubmitDataByHttpClientAndOrdinaryWay { /** * 使用get请求以普通方式提交数据 * @param map 传

分享Java常用几种加密算法(四种)_java

对称加密算法是应用较早的加密算法,技术成熟.在对称加密算法中,数据发信方将明文(原始数据)和加密密钥(mi yue)一起经过特殊加密算法处理后,使其变成复杂的加密密文发送出去.收信方收到密文后,若想解读原文,则需要使用加密用过的密钥及相同算法的逆算法对密文进行解密,才能使其恢复成可读明文.在对称加密算法中,使用的密钥只有一个,发收信双方都使用这个密钥对数据进行加密和解密,这就要求解密方事先必须知道加密密钥. 简单的java加密算法有: BASE 严格地说,属于编码格式,而非加密算法 MD(Mes

java备份数据库四种方法(mysql,mssql数据库备份)

java备份数据库教程四种方法(mysql教程,mssql数据库备份) mysql数据库备份的东西,然后研究了一下java语言中怎么来调用cmd的命令来实现mysqldump的备份功能.具体实现如下: 1.首先设置环境变量:有两种方式.第一种,在环境变量中添加 mysql_home,设置内容为 mysql的安装路径,然后,在path中添加路径  %mysql_home%bin    .第二种方法,不新建mysql_home,而是直接在path中添加   mysql安装路径bin .这样,调用cm

MS SQL Server数据库查询优化及分页算法

server|分页|数据|数据库|算法|优化 探讨如何在有着1000万条数据的MS SQL SERVER数据库中实现快速的数据提取和数据分页.以下代码说明了我们实例中数据库的"红头文件"一表的部分数据结构:CREATE TABLE [dbo].[TGongwen] (    --TGongwen是红头文件表名    [Gid] [int] IDENTITY (1, 1) NOT NULL ,--本表的id号,也是主键    [title] [varchar] (80) COLLATE

H股回归A股两类模式四种方案各显其能

苏江 陈智峰 去年10月21日,在香港主板上市的H股公司山东墨龙(0568.HK,002490.SZ)率先在中小板挂牌,此后大连港(601880.SH)和金隅股份(601992.SH)先后登陆沪市,而中国交通建设(1800.HK,下称中交股份)计划新发A股和换股吸收合并路桥建设(600263.SH)的预案也在去年最后一天公布,排在这之后的名单还包括两家汽车公司比亚迪股份(1211.HK)和长城汽车(2333.HK)--一切表明,在IPO重启一年之后H股回归A股又开始逐渐演变为一种趋势. 据不完全

如何测试端口通不通(四种方法)_linux shell

一般情况下使用"telnet ip port"判断端口通不通,其实测试方法不止这一种,还有很多种方法,下面小编给大家分享了几种方法,具体内容请往下看: 准备环境 启动一个web服务器,提供端口. [wyq@localhost ~]$ python -m SimpleHTTPServer 8080 Serving HTTP on 0.0.0.0 port 8080 ... 用其它web服务器提供端口也一样,由于python比较方便,这里就用它 1.使用telnet判断 telnet是wi

jsp 连接Oracle 数据库四种方法

package dbbean; import java.sql.*; public class contactbean{ private connection con; //初始化连接. public contactbean() {          try  {   class.forname("oracle.jdbc.driver.oracledriver").newinstance();   string url="jdbc:oracle:thin:@localhost

【开源】QuickPager ASP.NET2.0分页控件V2.0.0.1——支持多种数据库。让分页更加简单。

分页控件的源代码下载网址:http://www.cnblogs.com/jyk/archive/2008/04/25/1170979.html (在网页的下面) 下载文件里面由一个测试网页:http://localhost:5561/test/Testlist.aspx?fid=1 请注意后面的参数. 在webconfig里面修改连接字符串和数据库类型.DataType ---- 1: MS SQL ;2:Oledb:3:ODBC.   <appSettings>    <add key