|
|
当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”这句话有些欠妥,
至于为什么有这个现象的原因,想必大家应该都比较清楚了! |
|