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.看执行计划的时候不要被执行计划的基数给骗了----它可能显示是有误差的