楼主: DragonBill

[精华] ROWNUM与ORDER BY联用时对结果集的影响

[复制链接]
求职 : 信息技术经理/主管
论坛徽章:
24
授权会员
日期:2008-02-29 10:00:41秀才
日期:2016-01-25 14:55:31秀才
日期:2016-01-13 12:14:26紫蜘蛛
日期:2014-11-05 16:43:53ITPUB社区12周年站庆徽章
日期:2013-10-08 17:44:42ITPUB社区12周年站庆徽章
日期:2013-10-08 14:57:28ITPUB社区12周年站庆徽章
日期:2013-10-08 14:54:39红旗
日期:2013-09-05 15:55:56鲜花蛋
日期:2013-03-03 22:23:072013年新春福章
日期:2013-02-25 14:51:24
11#
发表于 2008-3-28 13:52 | 只看该作者
不错,收藏

使用道具 举报

回复
论坛徽章:
2
ERP板块每日发贴之星
日期:2005-11-17 01:01:47生肖徽章2007版:龙
日期:2008-04-07 19:41:09
12#
发表于 2008-3-28 14:09 | 只看该作者
学习了,太细了,佩服

使用道具 举报

回复
论坛徽章:
2
生肖徽章2007版:猪
日期:2008-02-25 09:49:28奥运会纪念徽章:羽毛球
日期:2008-05-24 11:31:29
13#
发表于 2008-3-28 14:48 | 只看该作者
    当ORDER BY字段为PRIMARY KEY时, 此时Oracle是先ORDER BY再对记录ROWNUM


为什么为这样呢?
呵呵,这里有个小"关子"

请看测试:
SQL> select * from a;

        ID
----------
         1
        10
         2
        20
         5
        50

6 rows selected.

SQL> alter table a add constraint con_t_pk primary key(id);

Table altered.

SQL> select * from a;

        ID
----------
         1
         2
         5
        10
        20
        50

6 rows selected.

SQL>
--发现加了主键后查询结果就自动排序了

SQL> set autot traceonly
SQL> select * from a;

6 rows selected.


Execution Plan
----------------------------------------------------------
Plan hash value: 1857226538

-----------------------------------------------------------------------------
| Id  | Operation        | Name     | Rows  | Bytes | Cost (%CPU)| Time     |
-----------------------------------------------------------------------------
|   0 | SELECT STATEMENT |          |     6 |    78 |     1   (0)| 00:00:01 |
|   1 |  INDEX FULL SCAN | CON_T_PK |     6 |    78 |     1   (0)| 00:00:01 |
-----------------------------------------------------------------------------

Note
-----
   - dynamic sampling used for this statement


Statistics
----------------------------------------------------------
          0  recursive calls
          0  db block gets
          2  consistent gets
          0  physical reads
          0  redo size
        476  bytes sent via SQL*Net to client
        385  bytes received via SQL*Net from client
          2  SQL*Net roundtrips to/from client
          0  sorts (memory)
          0  sorts (disk)
          6  rows processed

SQL>
--原来是走了INDEX FULL SCAN

SQL> select * from a where rownum<4 order by id;


Execution Plan
----------------------------------------------------------
Plan hash value: 1925392830

-----------------------------------------------------------------------------
| Id  | Operation        | Name     | Rows  | Bytes | Cost (%CPU)| Time     |
-----------------------------------------------------------------------------
|   0 | SELECT STATEMENT |          |     3 |    39 |     1   (0)| 00:00:01 |
|*  1 |  COUNT STOPKEY   |          |       |       |            |          |
|   2 |   INDEX FULL SCAN| CON_T_PK |     6 |    78 |     1   (0)| 00:00:01 |
-----------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   1 - filter(ROWNUM<4)

Note
-----
   - dynamic sampling used for this statement


Statistics
----------------------------------------------------------
          7  recursive calls
          0  db block gets
         20  consistent gets
          0  physical reads
          0  redo size
        452  bytes sent via SQL*Net to client
        385  bytes received via SQL*Net from client
          2  SQL*Net roundtrips to/from client
          0  sorts (memory)
          0  sorts (disk)
          3  rows processed

SQL>
--那么为什么select * from a where rownum<4 order by id;是先order by 主键再选取rownum<4的原因就一目了然了!

--即使有主键,如果不使用INDEX FULL SCAN会如何呢?
SQL> select /*+full(a)*/ * from a where rownum<4 order by id;


Execution Plan
----------------------------------------------------------
Plan hash value: 418636105

----------------------------------------------------------------------------
| Id  | Operation           | Name | Rows  | Bytes | Cost (%CPU)| Time     |
----------------------------------------------------------------------------
|   0 | SELECT STATEMENT    |      |     3 |    39 |     4  (25)| 00:00:01 |
|   1 |  SORT ORDER BY      |      |     3 |    39 |     4  (25)| 00:00:01 |
|*  2 |   COUNT STOPKEY     |      |       |       |            |          |
|   3 |    TABLE ACCESS FULL| A    |     6 |    78 |     3   (0)| 00:00:01 |
----------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   2 - filter(ROWNUM<4)

Note
-----
   - dynamic sampling used for this statement


Statistics
----------------------------------------------------------
          7  recursive calls
          0  db block gets
         22  consistent gets
          0  physical reads
          0  redo size
        452  bytes sent via SQL*Net to client
        385  bytes received via SQL*Net from client
          2  SQL*Net roundtrips to/from client
          1  sorts (memory)
          0  sorts (disk)
          3  rows processed

SQL> set autotrace off
SQL> select /*+full(a)*/ * from a where rownum<4 order by id;

        ID
----------
         1
         2
        10

SQL>
--发现走TABLE ACCESS FULL时结果还是先取rownum<4再order by id

所以“当ORDER BY字段为PRIMARY KEY时, 此时Oracle是先ORDER BY再对记录ROWNUM”这句话有些欠妥,
至于为什么有这个现象的原因,想必大家应该都比较清楚了!

使用道具 举报

回复
论坛徽章:
2
生肖徽章2007版:猪
日期:2008-02-25 09:49:28奥运会纪念徽章:羽毛球
日期:2008-05-24 11:31:29
14#
发表于 2008-3-28 15:13 | 只看该作者
原帖由 zhangfengh 于 2008-3-28 14:59 发表
把你的a表再加几个字段,看看select * from a时是不是还用INDEX FULL SCAN



不是,但select * from a where rownum<4 order by id是走INDEX FULL SCAN的,呵呵!
这个有关系么?我也没有一定会走INDEX FULL SCAN呀.

我想说的是:先执行order by 还是 rownum< 不是一定的,应该根据执行计划而定!

使用道具 举报

回复
论坛徽章:
18
生肖徽章2007版:虎
日期:2008-04-11 18:37:24奥运会纪念徽章:击剑
日期:2008-07-03 11:38:17迷宫蛋
日期:2011-05-10 13:03:40茶鸡蛋
日期:2011-05-10 13:05:16蜘蛛蛋
日期:2011-05-10 13:07:01灰彻蛋
日期:2012-12-10 11:47:16鲜花蛋
日期:2013-07-07 10:07:20
15#
 楼主| 发表于 2008-3-28 18:09 | 只看该作者
原帖由 zhangfengh 于 2008-3-28 15:16 发表
因为你的a表只有id这一个字段,而且主键就建立在它上面,所以select *时才会用到INDEX FULL SCAN,在索引中能够得到所有的结果,如果加几个字段,索引中得不到所有的结果,就不一定用INDEX FULL SCAN了



使用道具 举报

回复
论坛徽章:
0
16#
发表于 2008-3-31 09:16 | 只看该作者
大家可以看一下TOM的高效设计,其中有几页是专门讲rownum和order by 的.

使用道具 举报

回复
论坛徽章:
66
现任管理团队成员
日期:2011-05-07 01:45:08版主9段
日期:2013-04-21 02:21:02ITPUB年度最佳版主
日期:2014-02-19 10:05:27ITPUB年度最佳版主
日期:2013-01-30 17:30:25ITPUB年度最佳技术原创精华奖
日期:2012-03-13 17:12:05优秀写手
日期:2013-12-18 09:29:15元宝章
日期:2015-02-10 19:57:54金牌徽章
日期:2015-02-10 19:59:42银牌徽章
日期:2015-02-10 19:59:42铜牌徽章
日期:2015-02-10 19:59:41
17#
发表于 2008-3-31 11:17 | 只看该作者
1,对LZ的细致发现研究很支持
2,其实也没这么玄,查看下执行计划就知道为什么会出现这种情况了

使用道具 举报

回复
论坛徽章:
138
19周年集字徽章-19
日期:2020-06-08 08:30:56马上加薪
日期:2014-02-19 11:55:14马上有对象
日期:2014-02-19 11:55:14马上有钱
日期:2014-02-19 11:55:14马上有房
日期:2014-02-19 11:55:14马上有车
日期:2014-02-19 11:55:14马上有房
日期:2014-02-18 16:42:022014年新春福章
日期:2014-02-18 16:42:02路虎
日期:2013-11-22 12:26:18问答徽章
日期:2014-05-08 12:15:31
18#
发表于 2008-4-8 13:35 | 只看该作者

使用道具 举报

回复
论坛徽章:
5
奥运会纪念徽章:摔跤
日期:2008-07-02 08:48:392009日食纪念
日期:2009-07-22 09:30:00优秀写手
日期:2013-12-18 09:29:11SQL数据库编程大师
日期:2016-01-13 10:30:43SQL大赛参与纪念
日期:2016-01-13 10:32:19
19#
发表于 2008-5-22 11:04 | 只看该作者
只因为整理辛苦就可以加精华呀。。。
翻了翻,以前精华也不多,这个版人气也很足,加精理由似乎有些牵强

以上纯属个人看法,偶尊重版主的决定

btw:楼主辛苦

使用道具 举报

回复
论坛徽章:
20
复活蛋
日期:2011-07-16 16:19:54蜘蛛蛋
日期:2012-05-17 14:24:42蛋疼蛋
日期:2013-02-17 17:09:06咸鸭蛋
日期:2013-03-21 13:06:27蜘蛛蛋
日期:2013-04-16 10:52:24鲜花蛋
日期:2013-05-21 10:59:59鲜花蛋
日期:2013-05-22 17:18:10日产
日期:2013-11-12 10:17:44凯迪拉克
日期:2013-12-23 14:44:44
20#
发表于 2008-5-22 11:46 | 只看该作者
支持。辛苦LZ

使用道具 举报

回复

您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

TOP技术积分榜 社区积分榜 徽章 团队 统计 知识索引树 积分竞拍 文本模式 帮助
  ITPUB首页 | ITPUB论坛 | 数据库技术 | 企业信息化 | 开发技术 | 微软技术 | 软件工程与项目管理 | IBM技术园地 | 行业纵向讨论 | IT招聘 | IT文档
  ChinaUnix | ChinaUnix博客 | ChinaUnix论坛
CopyRight 1999-2011 itpub.net All Right Reserved. 北京盛拓优讯信息技术有限公司版权所有 联系我们 未成年人举报专区 
京ICP备16024965号-8  北京市公安局海淀分局网监中心备案编号:11010802021510 广播电视节目制作经营许可证:编号(京)字第1149号
  
快速回复 返回顶部 返回列表