create table page as select * from dba_objects;
create index idx_page on page(object_id);
create index idx_page_1 on page(owner,object_id);
create index idx_page_2 on page(owner);
create index idx_page_3 on page(object_id,owner);
BEGIN
DBMS_STATS.GATHER_TABLE_STATS(ownname => 'SCOTT',
tabname => 'PAGE',
estimate_percent => 100,
method_opt => 'for all columns size skewonly',
no_invalidate => FALSE,
degree => 4,
cascade => TRUE);
END;
select * from
(
select * from
(
select a.*,rownum rn
from page a
where object_id >1000 and owner='SYS'
order by object_id desc
) where rownum<=20
) where rn>=0;
分页语句必须要有order by ,order by 哪个列 哪个列必须有索引
只要 分页有 sort order by 绝对是错的
肯定没走索引
SQL> select * from
(
select * from
(
select a.*,rownum rn
from page a
where object_id >1000 and owner='SYS'
order by object_id desc
) where rownum<=20
) where rn>=0; 2 3 4 5 6 7 8 9 10
20 rows selected.
Execution Plan
----------------------------------------------------------
Plan hash value: 824209635
-----------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes |TempSpc| Cost (%CPU)| Time |
-----------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 20 | 4400 | | 910 (1)| 00:00:11 |
|* 1 | VIEW | | 20 | 4400 | | 910 (1)| 00:00:11 |
|* 2 | COUNT STOPKEY | | | | | | |
| 3 | VIEW | | 30424 | 6536K| | 910 (1)| 00:00:11 |
|* 4 | SORT ORDER BY STOPKEY| | 30424 | 2881K| 4000K| 910 (1)| 00:00:11 |
| 5 | COUNT | | | | | | |
|* 6 | TABLE ACCESS FULL | PAGE | 30424 | 2881K| | 234 (1)| 00:00:03 |
-----------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter("RN">=0)
2 - filter(ROWNUM<=20)
4 - filter(ROWNUM<=20)
6 - filter("OWNER"='SYS' AND "OBJECT_ID">1000)
Statistics
----------------------------------------------------------
1153 recursive calls
0 db block gets
1336 consistent gets
1036 physical reads
0 redo size
3175 bytes sent via SQL*Net to client
431 bytes received via SQL*Net from client
3 SQL*Net roundtrips to/from client
66 sorts (memory)
0 sorts (disk)
20 rows processed
分页语句:
1.必须有orderby
2.order by 哪个列,那个列就必须要有索引,利用索引已排序的特点。
3.分页有 sort order by 重新对数据进行排序
select * from
(
select * from
(
select /*+ index(a) */ a.*,rownum rn
from page a
where object_id >1000 and owner='SYS'
order by object_id desc
) where rownum<=20
) where rn>=0;
SQL> select * from table(dbms_xplan.display_cursor(null,null,'ALLSTATS LAST'));
PLAN_TABLE_OUTPUT
-------------------------------------------------------------------------------------------------------------------
-------------------------------------------------------------------------------------
SQL_ID 4tub4ucyfwk79, child number 0
-------------------------------------
select * from ( select * from ( select /*+ index(a) */ a.*,rownum rn
from page a where object_id >1000 and owner='SYS' order by object_id
desc ) where rownum<=20 ) where rn>=0
Plan hash value: 4010810952
-------------------------------------------------------------------------------------------------------------------
-----------------
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers | OMem |
1Mem | Used-Mem |
-------------------------------------------------------------------------------------------------------------------
-----------------
| 0 | SELECT STATEMENT | | 1 | | 20 |00:00:00.83 | 865 | |
| |
|* 1 | VIEW | | 1 | 20 | 20 |00:00:00.83 | 865 | |
| |
|* 2 | COUNT STOPKEY | | 1 | | 20 |00:00:00.83 | 865 | |
| |
| 3 | VIEW | | 1 | 30424 | 20 |00:00:00.83 | 865 | |
| |
|* 4 | SORT ORDER BY STOPKEY | | 1 | 30424 | 20 |00:00:00.83 | 865 | 1824K|
650K| 1621K (0)|
| 5 | COUNT | | 1 | | 29905 |00:00:00.65 | 865 | |
| |
|* 6 | TABLE ACCESS BY INDEX ROWID| PAGE | 1 | 30424 | 29905 |00:00:00.48 | 865 | |
| |
|* 7 | INDEX RANGE SCAN | IDX_PAGE_2 | 1 | 30835 | 30835 |00:00:00.10 | 66 | |
| |
-------------------------------------------------------------------------------------------------------------------
-----------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter("RN">=0)
2 - filter(ROWNUM<=20)
4 - filter(ROWNUM<=20)
6 - filter("OBJECT_ID">1000)
7 - access("OWNER"='SYS')
30 rows selected.
SORT ORDER BY STOPKEY 也是错的
select * from
(
select * from
(
select /*+ index_desc(a idx_page_3) */ a.*,rownum rn
from page a
where object_id >1000 and owner='SYS'
order by object_id desc
) where rownum<=20
) where rn>=0;
SQL> select * from table(dbms_xplan.display_cursor(null,null,'ALLSTATS LAST'));
PLAN_TABLE_OUTPUT
-------------------------------------------------------------------------------------------------------------------
-------------------------------------------------------------------------------------
SQL_ID 8vy3s6f4nh4ga, child number 0
-------------------------------------
select * from ( select * from ( select /*+ index_desc(a idx_page_3)
*/ a.*,rownum rn from page a where object_id >1000 and
owner='SYS' order by object_id desc ) where rownum<=20 ) where rn>=0
Plan hash value: 3526010999
------------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers | Reads |
------------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | | 20 |00:00:00.01 | 9 | 2 |
|* 1 | VIEW | | 1 | 20 | 20 |00:00:00.01 | 9 | 2 |
|* 2 | COUNT STOPKEY | | 1 | | 20 |00:00:00.01 | 9 | 2 |
| 3 | VIEW | | 1 | 30424 | 20 |00:00:00.01 | 9 | 2 |
| 4 | COUNT | | 1 | | 20 |00:00:00.01 | 9 | 2 |
| 5 | TABLE ACCESS BY INDEX ROWID | PAGE | 1 | 30424 | 20 |00:00:00.01 | 9 | 2 |
|* 6 | INDEX RANGE SCAN DESCENDING| IDX_PAGE_3 | 1 | 30424 | 20 |00:00:00.01 | 4 | 2 |
------------------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter("RN">=0)
2 - filter(ROWNUM<=20)
6 - access("OBJECT_ID" IS NOT NULL AND "OBJECT_ID">1000 AND "OWNER"='SYS')
filter("OWNER"='SYS')
28 rows selected.
多表关联后分页:
select ... from a,b where a.id=b.id order by a.xx;
a当驱动表 nl b
分页SQL必须走NL循环 order by 谁 谁当驱动表
1. 我们把它当成只 从a出数据
2.值给a.xx建索引
3.被驱动表 b b.id建索引
select ... from a,b where a.id=b.id order by a.xx,b.xxx;
分页的 每页 取 20条
这种SQL没法优化,order by 2个表没法优化
select ... from a,b where a.id=b.id gropu by ...order by 分页的 每页 取 20条
分页语句不能有group by ,distinct操作
select ... from a left join b where ... order by b
外链接 左链接 驱动表只能是a 那么order by a表
select ... from a where 过滤条件 order by 另外一个列
按where 条件列+order by 列创建索引
select ... from a where owner='SB' and xx like '%jj%' order by money
这个时候建索引:money,owner,xx
分页语句的优化技巧:
1.分页SQL要想快最好走索引,根据order by asc/desc ,用hint index_asc/index_desc
强制它走索引INDEX FULL SCAN DESCENDING/INDEX RANGE SCAN DESCENDING
2.不要让Oracle扫描整个index,确保只扫描一部分索引块,然后回表就取得数据,然后
就count stopkey
3.一定要确保索引回表的时候不要在表上再去过滤,也就是说TABLE ACCESS BY INDEX ROWID
上面没*,不然就可能扫描整个索引块,根据where条件可以创建组合索引
(分区表要创建global index)
4.看执行计划的时候不要被执行计划的基数给骗了----它可能显示是有误差的