在MySQL中,我们通常用极限来完成分页操作的数据采集,并在Oracle数据库,和不方便的方法如极限实现分页,所以我们通常完成分页SQL语句中的直接,这就要求rownum的帮助(row_number)或伪列函数。本文将展示使用rownum(row_number)和伪列的方法来分析具体的功能完整的Oracle数据分页操作,并与两性能分析比较。

首先,初始化测试数据

首先,我选择了70000个数据在数据字典中all_objects表。下面是以下步骤:

复制代码代码如下所示:

为了方便结果集的验证,避免不必要的排序,我使用rownum直接产生一个有序的object_id柱

SQL >创建表my_objects作为

2行号为object_id,object_name,object_type

3,从all_objects rownum < 70001;

表的创建。

-设置为ojbect_id列主键

SQL> ALTER TABLE my_objects添加主键(object_id);

表的改变。

SQL select count(*)>从my_objects;

计数(*)

----------

七万

-分析表

SQL> exec dbms_stats.gather_table_stats(用户,'my_objects,级联= true);

已成功完成。



两。分页数据采集

完成分页,我们需要在这台有10记录的第59991-60000,我们使用rownum和rown_number()来实现

复制代码代码如下所示:

方法1,ROWNUM伪列模式

SQL >选择T *(选择D *,rownum民从my_objects d);

object_id object_name object_type Num

---------------------------------------------------------------------

59991 / 585bb929_dicomrepos24 java类59991

59992 / 13a1874f_dicomrepos25 java类59992

59993 / 2322ccf0_dicomrepos26 java类59993

59994 / 6c82abc6_dicomrepos27 java类59994

59995 / 34be1a57_dicomrepos28 java类59995

59996 / b7ee0c7f_dicomrepos29 java类59996

59997 / bb1d935c_dicomrepos30 java类59997

59998 / deb95b4f_dicomrepos31 java类59998

59999 / 9b5f55c0_dicomrepos32 java类59999

60000 / 572f1657_dicomrepos33 java类60000

选择10行。

方法二,row_number分析功能的方法

从中选择

2(选择T *,row_number()以上(以t.object_id)为民

3从my_objects T)

4在59991到60000之间的数字;

object_id object_name object_type Num

---------------------------------------------------------------------

59991 / 585bb929_dicomrepos24 java类59991

59992 / 13a1874f_dicomrepos25 java类59992

59993 / 2322ccf0_dicomrepos26 java类59993

59994 / 6c82abc6_dicomrepos27 java类59994

59995 / 34be1a57_dicomrepos28 java类59995

59996 / b7ee0c7f_dicomrepos29 java类59996

59997 / bb1d935c_dicomrepos30 java类59997

59998 / deb95b4f_dicomrepos31 java类59998

59999 / 9b5f55c0_dicomrepos32 java类59999

60000 / 572f1657_dicomrepos33 java类60000

选择10行。



你可以看到这两个方法来返回正确的结果集;在行号的方法,因为不能直接使用ROWNUM伪列大于比较操作,所以这里是第一个使用rownum获得60000数据的查询,然后用手术去除外查询不需要的行的。row_number()方法,row_number()分析功能由object_id产生独特的身份分类。然后,可以用中间的方式以方便的方式获得区间数据。实际执行是这样吗让我们简单地分析一下这两个细节。

三,寻呼性能分析

首先,看看他们的实施计划:

复制代码代码如下所示:

SQL > AutoTrace traceonly

SQL >设置线宽200

ROWNUM伪列的分页的执行计划

SQL >选择T *(选择D *,rownum民从my_objects d);

选择10行。

执行计划

----------------------------------------------------------

计划哈希值:341064162

----------------------------------------------------------------------------------

我的名字|操作| | |行| |字节成本(CPU)时间| |

----------------------------------------------------------------------------------

| 0 | SELECT语句| | | 60000 3164k | 103(0)| 00:00:02 |

|×1 |观| | | 60000 3164k | 103(0)| 00:00:02 |

|×2 |计数stopkey | | | | | |

3表访问全| my_objects | | | | 60000 2226k | 103(0)| 00:00:02 |

----------------------------------------------------------------------------------

谓词信息(由操作ID标识):

离开

1过滤器(T)。数字> = 59991)

2过滤器(rownum <= 60000)

统计

----------------------------------------------------------

163递归调用

0分贝块得到

399一致的获取

0物理读

0重做日志大小

1030个字节通过网络发送给客户机

从客户端接收的419个字节

2 SQL*Net切换到/从客户端

5类(内存)

0类(磁盘)

10行处理

- row_number执行计划()分页

从中选择

2(选择T *,row_number()以上(以t.object_id)为民

3从my_objects T)

4在59991到60000之间的数字;

选择10行。

执行计划

----------------------------------------------------------

计划哈希值:2942654422

----------------------------------------------------------------------------------------------

我的名字|操作| | |行| |字节成本(CPU)时间| |

----------------------------------------------------------------------------------------------

| 0 | SELECT语句| | | 70000 3691k | 565(1)| 00:00:07 |

|×1 |观| | | 70000 3691k | 565(1)| 00:00:07 |

2窗口NOSORT stopkey | * | | | | 70000 2597k | 565(1)| 00:00:07 |

通过索引rowid | my_objects | | | 70000 2597k | 565访问| 3表(1)| 00:00:07 |

4索引全扫描| | | sys_c0011057 | 70000 | | 146(0)| 00:00:02 |

----------------------------------------------------------------------------------------------

谓词信息(由操作ID标识):

离开

1 -筛选器()> 59991和< = 60000)

2过滤器(row_number()在(由T。object_id )< = 60000)

统计

----------------------------------------------------------

1递归调用

0分贝块得到

490一致的获取

0物理读

0重做日志大小

1030个字节通过网络发送给客户机

从客户端接收的419个字节

2 SQL*Net切换到/从客户端

0类(内存)

0类(磁盘)

10行处理



从以上的执行计划,我们可以看到,使用全表的前60000行获得扫描表的行号的方法,然后用t.num > = 59991谓词过滤掉不需要的线;和(row_number)方法被用于分析主键索引保存自己从窗口排序操作功能却得到所有表中的70000行,然后用此操作之间的关键字来过滤数据,大量的资源消耗在读取数据,所以在上面的例子中,ROWNUM伪列的方法来获得好的性能,但事实上,在大多数情况下,第一该行号的方法可以得到更好的性能。

它可能会受到质疑,因为row_number()方法已经花了太多的资源,对数据的读取,为什么不直接扫描整个表,让我们在使用全表扫描的情况看。

复制代码代码如下所示:

-直接禁用主键

SQL> ALTER TABLE my_objects禁用主键;

表的改变。

从中选择

2(选择T *,row_number()以上(以t.object_id)为民

3从my_objects T)

4在59991到60000之间的数字;

选择10行。

执行计划

----------------------------------------------------------

计划哈希值:2855691782

-----------------------------------------------------------------------------------------------

我的名字|操作| | |行|字节| tempspc |成本(CPU)时间| |

-----------------------------------------------------------------------------------------------

| 0 | SELECT语句| | | | 70000 3691k | 812(1)| 00:00:10 |

|×1 |观| | | | 70000 3691k | 812(1)| 00:00:10 |

2窗口排序推秩| | * | | | 2597k | 70000 3304k | 812(1)| 00:00:10 |

3表访问全| | | my_objects | | | 70000 2597k | 120(1)| 00:00:02 |

-----------------------------------------------------------------------------------------------

谓词信息(由操作ID标识):

离开

1 -筛选器()> 59991和< = 60000)

2过滤器(row_number()在(由T。object_id )< = 60000)

统计

----------------------------------------------------------

190递归调用

0分贝块得到

450一致的获取

0物理读

0重做日志大小

1030个字节通过网络发送给客户机

从客户端接收的419个字节

2 SQL*Net切换到/从客户端

6类(内存)

0类(磁盘)

10行处理



可以看出,门窗类推秩方法发生在全表扫描的情况下,这意味着CPU资源也将在object_id分类。虽然object_id命令在这种情况下,性能是没有行号模式好。

所以,在写作的过程中,我还是更喜欢使用以下rownum完成Oracle分页操作,通常写成如下:

复制代码代码如下所示:

-返回第二十页数据,每页10行

SQL >定义pagenum = 20

SQL >定义pagerecord = 10

SQL >选择T *(选择D *,rownum民从my_objects D

2在rownum <= pagerecord * pagenum T)

3在t.num > =(pagenum-1)* pagerecord + 1;

2岁:在rownum <= pagerecord * pagenum)T

2:在行号< = 10 * 20)T

3岁:在t.num > =(pagenum-1)* pagerecord + 1

3:在t.num > =(20-1)* 10 + 1

object_id object_name object_type Num

---------------------------------------------------------------------

191 sqlobj data_pkey美元指数191

192 sqlobj auxdata表192美元

193 i_sqlobj auxdata_pkey美元指数193

194 i_sqlobj auxdata_task美元指数194

195 object_usage表195

196 i_stats_obj #指数196

197程序$表197

198 procedureinfo表198美元

199参数$表199

200源表200美元

选择10行。



备注:uff1a

为了使程序更容易理解,有人会利用之间在rownum方法限制数据线。

复制代码代码如下所示:

选择T *(行号num,D * my_objects D)T。



在他们看来,数据行用这种方式与第一rownum方法一致。Oracle将部分之间的谓词推到子查询,也不会影响性能。这个想法完全错了。让我们看看它的具体执行计划。

复制代码代码如下所示:

SQL >选择T *(行号num,D * my_objects D)T.

选择10行。

执行计划

----------------------------------------------------------

计划哈希值:1665864874

----------------------------------------------------------------------------------

我的名字|操作| | |行| |字节成本(CPU)时间| |

----------------------------------------------------------------------------------

| 0 | SELECT语句| | | 70000 3691k | 120(1)| 00:00:02 |

|×1 |观| | | 70000 3691k | 120(1)| 00:00:02 |

| 2 |计数| | | | | |

3表访问全| my_objects | | | | 70000 2597k | 120(1)| 00:00:02 |

----------------------------------------------------------------------------------

谓词信息(由操作ID标识):

离开

1过滤器(T)。== 59991)

统计

----------------------------------------------------------

0递归调用

0分贝块得到

423 consistent gets

0物理读

0重做日志大小

1030个字节通过网络发送给客户机

从客户端接收的419个字节

2 SQL*Net切换到/从客户端

0类(内存)

0类(磁盘)

10行处理



你可以看到这个非常抢眼的查询首先发生全表扫描70000行,60000行是没有预期,或行号,行号在子查询中使用的直接禁用查询转换期前谓词的推动作用,因此上述查询可以先使用之间的过滤获得的所有数据。可以参考我CBO的探究转换查询。

说了这么多,其实是三个sql语句的oracle分页,分页问题的数据量非常大,它不仅效率高,因此还需要借助其他一些技术,如反范型的设计、预计算或在应用层建立合适的缓存机制。