1. Application in a separate query returns a lot of combinations query returns very little.
2. The combined sequential combination of the query, to fully consider the case of a separate inquiry
3. only non-equivalent range queries, the combination does not affect the performance index order
4. The combination index column before the preferred sequence generally opposite the column equivalent query.
5. Note that the combination index in combination with optimized conditions of about IN
! Composite index through the elements / * 1. applicable in the case of a single query returns many records, suddenly after a combination of query returns a few records: for example, where a master's degree = return a lot of records , such as where career also returns a lot of cashiers = record so no matter which conditions do query the index, are inappropriate. However, if the degree is a master's, professional and at the same time is a cashier, she returned extremely rare. So joint index so we can start to build up. * / / * 2. The combined sequential combination inquiry, to consider the individual circumstances prefix query (or queries prefix index alone will not be effective or can only be used to jump index) such as when you build id, object_type joint index, depending on consider a separate query where id = xxx much, or more than alone where object_type queries. * / . --3 only when no equivalent range queries, the combination index order does not affect the performance (such as where col1 = xxx and col2 = xxx , regardless COL1 + COL2 composition or compositions COL2 + COL1) drop purge Table T; Create Table T SELECT * from dba_objects AS; INSERT INTO SELECT * T from T; INSERT INTO SELECT * T from T; INSERT INTO SELECT * T from T; Update object_id = T SET rownum; the commit; create index idx_id_type on t(object_id,object_type); create index idx_type_id on t(object_type,object_id); set autotrace off alter session set statistics_level=all ; set linesize 366 --性能和哪列在前没有什么差别 select /*+index(t,idx_id_type)*/ * from t where object_id=20 and object_type='TABLE'; select * from table(dbms_xplan.display_cursor(null,null,'allstats last')); ----------------------------------------------------------------------------------------------------- | Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers | ----------------------------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 1 | | 1 |00:00:00.01 | 5 | | 1 | TABLE ACCESS BY INDEX ROWID| T | 1 | 57 | 1 |00:00:00.01 | 5 | |* 2 | INDEX RANGE SCAN | IDX_ID_TYPE | 1 | 9 | 1 |00:00:00.01 | 4 | ----------------------------------------------------------------------------------------------------- select /*+index(t,idx_type_id)*/ * from t where object_id=20 and object_type='TABLE'; select * from table(dbms_xplan.display_cursor(null,null,'allstats last')); Plan hash value: 3420768628 ----------------------------------------------------------------------------------------------------- | Id | Operation | the Name | Starts | E-the Rows | A-the Rows | A-Time | Buffers | SELECT / * index + (T, idx_id_type) * / T * from WHERE object_id> = 20 and object_id <2000 and object_type = 'TABLE'; ----------------------------------------------------------------------------------------------------- | 0 | the SELECT a STATEMENT | | 1 | | 1 | 00: 00: 00.01 | 5 | | 1 | TABLE ACCESS BY INDEX the ROWID | T | 1 | 57 | 1 | 00: 00: 00.01 | 5 | | * 2 | INDEX SCAN RANGE | IDX_TYPE_ID | 1 | 9 | 1 | 00: 00: 00.01 | 4 | ------------------------------- -------------------------------------------------- -------------------- - 4. compositions generally preferred sequence index is equivalent to the column before the column opposite the query. (Combination index test case conditions ranging case, the condition is often unequal to be on the back, so that the front equivalent) SELECT * from Table (dbms_xplan.display_cursor (null, null, 'Last allstats ')); ---------------------------------------------- -------------------------------------------------- ----- | Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers | ----------------------------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 1 | | 469 |00:00:00.01 | 86 | | 1 | TABLE ACCESS BY INDEX ROWID| T | 1 | 14 | 469 |00:00:00.01 | 86 | |* 2 | INDEX RANGE SCAN | IDX_ID_TYPE | 1 | 1 | 469 |00:00:00.01 | 40 | ----------------------------------------------------------------------------------------------------- select /*+index(t,idx_type_id)*/ * from t where object_id>=20 and object_id<2000 and object_type='TABLE'; -------------------------------------------------- -------------------------------------------------- - | Id | Operation | the Name | Starts | E-the Rows | A-the Rows | A-Time | Buffers | -------------------------- -------------------------------------------------- ------------------------- | 0 | the SELECT a STATEMENT | | 1 | | 469 | 00: 00: 00.01 | 81 | | 1 | TABLE ACCESS the ROWID INDEX BY | T | 1 | 469 | 469 | 00: 00: 00.01 | 81 | |* 2 | INDEX RANGE SCAN | IDX_TYPE_ID | 1 | 469 | 469 |00:00:00.01 | 35 | ------------------------------ -------------------------------------------------- --------------------- --5 Note combination index optimization conditions on the composition of iN. - case. 1 the UPDATE T = 20 is the SET the OBJECT_ID the WHERE ROWNUM <= 26000; The UPDATE T the SET the OBJECT_ID = 21 is the WHERE the OBJECT_ID <> 20 is; a COMMIT; SET LINESIZE 1000 SET pageSize. 1 ALTER the session SET STATISTICS_LEVEL = All; SELECT / * + index (T, idx1_object_id) * / * from T WHERE object_type = 'TABLE' the AND the OBJECT_ID > = 20 OBJECT_ID the aND <= 21; . --6 case 2 - is still on the optimization of iN (index case col1, col2, col3, and if not given query condition is cOL2, cOL3 test can only play a role) drop Table T purge; Create Table T AS SELECT * from dba_objects; the UPDATE T the SET the oBJECT_ID = 20 is the WHERE rOWNUM <= 26000; the UPDATE the OBJECT_ID the SET T = 21 WHERE OBJECT_ID <> 20; the Update T SET object_id = 22 is WHERE rownum <= 10000; a COMMIT; Create index idx_union ON T (object_type, object_id, owner); SET OFF AUTOTRACE ALTER SET STATISTICS_LEVEL = All the session; SET LINESIZE 1000 select * from t where object_type='VIEW' and OWNER='LJB'; select * from table(dbms_xplan.display_cursor(null,null,'allstats last')); select /*+INDEX(T,idx_union)*/ * from t T where object_type='VIEW' and OBJECT_ID IN (20,21,22) AND OWNER='LJB'; select * from table(dbms_xplan.display_cursor(null,null,'allstats last'));
Partition table all kinds of polymerization optimization:
-- 范围分区示例 drop table range_part_tab purge; --注意,此分区为范围分区 --例子1 create table range_part_tab (id number,deal_date date,area_code number,nbr number,contents varchar2(4000)) partition by range (deal_date) ( partition p_201301 values less than (TO_DATE('2013-02-01', 'YYYY-MM-DD')), partition p_201302 values less than (TO_DATE('2013-03-01', 'YYYY-MM-DD')), partition p_201303 values less than (TO_DATE('2013-04-01', 'YYYY-MM-DD')), partition p_201304 values less than (TO_DATE('2013-05-01', 'YYYY-MM-DD')), partition p_201305 values less than (TO_DATE('2013-06-01', 'YYYY-MM-DD')), partition p_201306 values less than (TO_DATE('2013-07-01', 'YYYY-MM-DD')), partition p_201307 values less than (TO_DATE('2013-08-01', 'YYYY-MM-DD')), partition p_201308 values less than (TO_DATE('2013-09-01', 'YYYY-MM-DD')), partition p_201309 values less than (TO_DATE('2013-10-01', 'YYYY-MM-DD')), partition p_201310 values less than (TO_DATE('2013-11-01', 'YYYY-MM-DD')), partition p_201311 values less than (TO_DATE('2013-12-01', 'YYYY-MM-DD')), partition p_201312 values less than (TO_DATE('2014-01-01', 'YYYY-MM-DD')), partition p_201401 values less than (TO_DATE('2014-02-01', 'YYYY-MM-DD')), Within last values less p_201402 Partition (the TO_DATE ( '2014-03-01', 'YYYY-the MM-DD')), Partition P_max values less Within last (MAXVALUE) ) ; ALTER NBR Not Modify Table RANGE_PART_TAB null; - The following is inserted 2013 throughout the year and the date of random numbers indicate Fujian number meaning (591-599) of a random number of records, a total of 100,000, as follows: INSERT INTO range_part_tab (the above mentioned id, deal_date, area_code, nbr, Contents) the SELECT rownum, to_date (the TO_CHAR ( 365-SYSDATE, 'J') + TRUNC (DBMS_RANDOM.VALUE (0,365)), 'J'), ceil (DBMS_RANDOM.VALUE (591,599)), ceil (DBMS_RANDOM.VALUE (18900000001,18999999999)), RPAD ( '* ', 400,' * ') from Dual Connect by rownum <= 100000; the commit; - the following is inserted throughout the year 2014, the random number and the date indicates Fujian area Code meaning (591-599) of a random number of records, a total of 100,000, as follows: INSERT INTO range_part_tab (the above mentioned id, deal_date, area_code, nbr, Contents) the SELECT rownum, to_date( to_char(sysdate,'J')+TRUNC(DBMS_RANDOM.VALUE(0,365)),'J'), ceil(dbms_random.value(591,599)), ceil(dbms_random.value(18900000001,18999999999)), rpad('*',400,'*') from dual connect by rownum <= 100000; commit; create index idx_part_id on range_part_tab (id) ; create index idx_part_nbr on range_part_tab (nbr) local; - statistical information systems generally automatic collection, this is the first time after the completion of the table need to operate it, in order to facilitate testing exec dbms_stats.gather_table_stats(ownname => 'LJB',tabname => 'RANGE_PART_TAB',estimate_percent => 10,method_opt=> 'for all indexed columns',cascade=>TRUE) ; Implementation Plan the SELECT max (nbr) max_nbr from range_part_tab Partition (p_201305); the SET LINESIZE 1000 ON AUTOTRACE the SET ------------------------------------------------------------------------------------------------------------ | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | Pstart| Pstop | ------------------------------------------------------------------------------------------------------------ | 0 | SELECT STATEMENT | | 1 | 8 | 2 (0)| 00:00:01 | | | | 1 | SORT AGGREGATE | | 1 | 8 | | | | | | 2 | PARTITION RANGE SINGLE | | 1 | 8 | 2 (0)| 00:00:01 | 5 | 5 | | 3 | INDEX FULL SCAN (MIN/MAX)| IDX_PART_NBR | 1 | 8 | 2 (0)| 00:00:01 | 5 | 5 | ------------------------------------------------------------------------------------------------------------ 统计信息 ---------------------------------------------------------- 0 recursive calls 0 db block gets 2 consistent gets select max(nbr) max_nbr from range_part_tab where deal_date >= TO_DATE('2013-05-01', 'YYYY-MM-DD') and deal_date < TO_DATE('2013-06-01', 'YYYY-MM-DD'); 执行计划 ---------------------------------------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | Pstart| Pstop | ---------------------------------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 1 | 17 | 170 (0)| 00:00:03 | | | | 1 | SORT AGGREGATE | | 1 | 17 | | | | | | 2 | PARTITION RANGE SINGLE| | 22 | 374 | 170 (0)| 00:00:03 | 5 | 5 | | 3 | TABLE ACCESS FULL | RANGE_PART_TAB | 22 | 374 | 170 (0)| 00:00:03 | 5 | 5 | ---------------------------------------------------------------------------------------------------------- 统计信息 ---------------------------------------------------------- 0 recursive calls Block the gets db 0 568 consistent the gets the SELECT COUNT (*) max_nbr from range_part_tab Partition (p_201305); Implementation Plan ------------------------------------------------------------------------------------------------ | Id | Operation | Name | Rows | Cost (%CPU)| Time | Pstart| Pstop | ---------------------------- -------------------------------------------------- ------------------ | 0 | the SELECT a STATEMENT | | 1 | 8 (0) | 00:00:01 | | | | 1 | SORT AGGREGATE | | 1 | | | | | | 2 | the PARTITION the RANGE SINGLE | | 8716 |. 8 (0) | 00:00:01 |. 5 |. 5 | |. 3 | the INDEX the FAST SCAN FULL | IDX_PART_NBR | 8716 |. 8 (0) | 00:00:01 | 5 | 5 | --------------------------------------------- -------------------------------------------------- - statistics ---------------------------------------------------------- 0 recursive calls 0 db block gets 29 consistent gets select count(*) max_nbr from range_part_tab where deal_date >= TO_DATE('2013-05-01', 'YYYY-MM-DD') and deal_date < TO_DATE('2013-06-01', 'YYYY-MM-DD'); 执行计划 ---------------------------------------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | Pstart| Pstop | ---------------------------------------------------------------------------------------------------------- | 0 | a STATEMENT the SELECT | |. 1 |. 9 | 170. (0) | 00:00:03 | | | | 1 | SORT AGGREGATE | | 1 | 9 | | | | | | 2 | PARTITION RANGE SINGLE| | 22 | 198 | 170 (0)| 00:00:03 | 5 | 5 | |. 3 | the ACCESS TABLE FULL | RANGE_PART_TAB | 22 is | 198 | 170. (0) | 00:00:03 |. 5 | 5 | ------------------------------------------------ -------------------------------------------------- -------- statistics ---------------------------------------- ------------------ 0 recursive This Calls 0 db Block the gets 568 consistent the gets the SELECT SUM (nbr) max_nbr from range_part_tab Partition (p_201305); Implementation plan ------- -------------------------------------------------- ----------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | Pstart| Pstop | -------------------------------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 1 | 8 | 8 (0)| 00:00:01 | | | | 1 | SORT AGGREGATE | | 1 | 8 | | | | | | 2 | PARTITION RANGE SINGLE| | 8716 | 69728 | 8 (0)| 00:00:01 | 5 | 5 | | 3 | INDEX FAST FULL SCAN | IDX_PART_NBR | 8716 | 69728 | 8 (0)| 00:00:01 | 5 | 5 | -------------------------------------------------------------------------------------------------------- 统计信息 ---------------------------------------------------------- 0 recursive calls 0 db block gets 29 consistent gets select sum(nbr) max_nbr from range_part_tab where deal_date >= TO_DATE('2013-05-01', 'YYYY-MM-DD') and deal_date < TO_DATE('2013-06-01', 'YYYY-MM-DD'); 执行计划 ---------------------------------------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | Pstart| Pstop | ---------------------------------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 1 | 17 | 170 (0)| 00:00:03 | | | | 1 | SORT AGGREGATE | | 1 | 17 | | | | | | 2 | the PARTITION the RANGE SINGLE | | 22 is | 374 | 170. (0) | 00:00:03 |. 5 |. 5 | |. 3 | the ACCESS TABLE FULL | RANGE_PART_TAB | 22 is | 374 | 170. (0) | 00:00:03 | 5 | 5 | --------------------------------------------- -------------------------------------------------- ----------- statistics ------------------------------------- --------------------- 0 recursive This Calls 0 db Block the gets 568 consistent the gets the SELECT DISTINCT (nbr) from range_part_tab Partition (p_201305); Implementation plan ----- -------------------------------------------------- ------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | Pstart| Pstop | -------------------------------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 8660 | 69280 | 9 (12)| 00:00:01 | | | | 1 | HASH UNIQUE | | 8660 | 69280 | 9 (12)| 00:00:01 | | | | 2 | PARTITION RANGE SINGLE| | 8716 | 69728 | 8 (0)| 00:00:01 | 5 | 5 | | 3 | INDEX FAST FULL SCAN | IDX_PART_NBR | 8716 | 69728 | 8 (0)| 00:00:01 | 5 | 5 | -------------------------------------------------------------------------------------------------------- 统计信息 ---------------------------------------------------------- 0 recursive calls 0 db block gets 29 consistent gets 0 physical reads 0 redo size 152890 bytes sent via SQL*Net to client 6741 bytes received via SQL*Net from client 577 SQL*Net roundtrips to/from client 0 sorts (memory) 0 sorts (disk) 8635 rows processed select distinct(nbr) from range_part_tab where deal_date >= TO_DATE('2013-05-01', 'YYYY-MM-DD') and deal_date < TO_DATE('2013-06-01', 'YYYY-MM-DD'); | Id | Operation | the Name | the Rows | Bytes | Cost (% the CPU) | Time | Pstart | Pstop | ------------------------------------------------ -------------------------------------------------- -------- Implementation plan ---------------------------------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 22 | 374 | 171 (1)| 00:00:03 | | | | 1 | HASH UNIQUE | | 22 | 374 | 171 (1)| 00:00:03 | | | | 2 | PARTITION RANGE SINGLE| | 22 | 374 | 170 (0)| 00:00:03 | 5 | 5 | | 3 | TABLE ACCESS FULL | RANGE_PART_TAB | 22 | 374 | 170 (0)| 00:00:03 | 5 | 5 | ---------------------------------------------------------------------------------------------------------- 统计信息 ---------------------------------------------------------- 0 recursive calls 0 db block gets 568 consistent gets 0 physical reads 0 redo size 152886 bytes sent via SQL*Net to client 6741 bytes received via SQL*Net from client 577 SQL*Net roundtrips to/from client 0 sorts (memory) 0 sorts (disk) 8635 rows processed ---<=和<,<=扫描了两个分区 select count(*) from range_part_tab where deal_date >= TO_DATE('2013-05-01 00:00:00', 'YYYY-MM-DD hh24:mi:ss') and deal_date <= TO_DATE('2013-06-01 00:00:00', 'YYYY-MM-DD hh24:mi:ss'); COUNT(*) ---------- 8635 执行计划 ------------------------------------------------------------------------------------------------------------ | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | Pstart| Pstop | ------------------------------------------------------------------------------------------------------------ | 0 | SELECT STATEMENT | | 1 | 9 | 340 (1)| 00:00:05 | | | | 1 | SORT AGGREGATE | | 1 | 9 | | | | | | 2 | PARTITION RANGE ITERATOR| | 497 | 4473 | 340 (1)| 00:00:05 | 5 | 6 | |* 3 | TABLE ACCESS FULL | RANGE_PART_TAB | 497 | 4473 | 340 (1)| 00:00:05 | 5 | 6 | ------------------------------------------------------------------------------------------------------------ 统计信息 ---------------------------------------------------------- 0 recursive calls 0 db block gets 1136 consistent gets select count(*) from range_part_tab where deal_date >= TO_DATE('2013-05-01 00:00:00', 'YYYY-MM-DD hh24:mi:ss') and deal_date < TO_DATE('2013-06-01 00:00:00', 'YYYY-MM-DD hh24:mi:ss'); COUNT(*) ---------- 8635 执行计划 ---------------------------------------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | Pstart| Pstop | ---------------------------------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 1 | 9 | 170 (0)| 00:00:03 | | | | 1 | SORT AGGREGATE | | 1 | 9 | | | | | | 2 | PARTITION RANGE SINGLE| | 22 | 198 | 170 (0)| 00:00:03 | 5 | 5 | | 3 | TABLE ACCESS FULL | RANGE_PART_TAB | 22 | 198 | 170 (0)| 00:00:03 | 5 | 5 | ---------------------------------------------------------------------------------------------------------- 统计信息 ---------------------------------------------------------- 0 recursive calls 0 db block gets 568 consistent gets
When are low but partition index performance:
drop table part_tab purge; create table part_tab (id int,col2 int,col3 int) partition by range (id) ( partition p1 values less than (10000), partition p2 values less than (20000), partition p3 values less than (30000), partition p4 values less than (40000), partition p5 values less than (50000), partition p6 values less than (60000), partition p7 values less than (70000), partition p8 values less than (80000), partition p9 values less than (90000), partition p10 values less than (100000), partition p11 values less than (maxvalue) ) ; insert into part_tab select rownum,rownum+1,rownum+2 from dual connect by rownum <=110000; commit; create index idx_par_tab_col2 on part_tab(col2) local; create index idx_par_tab_col3 on part_tab(col3) ; drop table norm_tab purge; create table norm_tab (id int,col2 int,col3 int); insert into norm_tab select rownum,rownum+1,rownum+2 from dual connect by rownum <=110000; commit; create index idx_nor_tab_col2 on norm_tab(col2) ; create index idx_nor_tab_col3 on norm_tab(col3) ; set autotrace traceonly set linesize 1000 set timing on select * from part_tab where col2=8 ; 执行计划 ----------------------------------------------------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | Pstart| Pstop | ----------------------------------------------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 1 | 39 | 13 (0)| 00:00:01 | | | | 1 | PARTITION RANGE ALL | | 1 | 39 | 13 (0)| 00:00:01 | 1 | 11 | | 2 | TABLE ACCESS BY LOCAL INDEX ROWID| PART_TAB | 1 | 39 | 13 (0)| 00:00:01 | 1 | 11 | |* 3 | INDEX RANGE SCAN | IDX_PAR_TAB_COL2 | 1 | | 12 (0)| 00:00:01 | 1 | 11 | ----------------------------------------------------------------------------------------------------------------------- 统计信息 ---------------------------------------------------------- 0 recursive calls 0 db block gets 24 consistent gets 0 physical reads 0 redo size 539 bytes sent via SQL*Net to client 416 bytes received via SQL*Net from client 2 SQL*Net roundtrips to/from client 0 sorts (memory) 0 sorts (disk) 1 rows processed select * from norm_tab where col2=8 ; 执行计划 ------------------------------------------------------------------------------------------------ | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | ------------------------------------------------------------------------------------------------ | 0 | SELECT STATEMENT | | 1 | 39 | 2 (0)| 00:00:01 | | 1 | TABLE ACCESS BY INDEX ROWID| NORM_TAB | 1 | 39 | 2 (0)| 00:00:01 | |* 2 | INDEX RANGE SCAN | IDX_NOR_TAB_COL2 | 1 | | 1 (0)| 00:00:01 | ------------------------------------------------------------------------------------------------ 统计信息 ---------------------------------------------------------- 0 recursive calls 0 db block gets 4 consistent gets 0 physical reads 0 redo size 543 bytes sent via SQL*Net to client 416 bytes received via SQL*Net from client 2 SQL*Net roundtrips to/from client 0 sorts (memory) 0 sorts (disk) 1 rows processed select * from part_tab where col2=8 and id=2; select * from norm_tab where col2=8 and id=2; --查看索引高度等信息 select index_name, blevel, leaf_blocks, num_rows, distinct_keys, clustering_factor from user_ind_statistics where table_name in( 'NORM_TAB'); index_name SELECT, blevel, leaf_blocks, NUM_ROWS, distinct_keys, of clustering_factor the FROM USER_IND_PARTITIONS index_name like WHERE 'IDX_PAR_TAB%'; height affects performance index ---
At the same time take the case of minimum and maximum values:
MAX / MIN index optimization drop Table T purge; Create Table T AS SELECT * from dba_objects; Update T SET object_id = rownum; the commit; ALTER Table T the Add constraint pk_object_id Primary Key (the OBJECT_ID); SET AUTOTRACE ON SET LINESIZE 1000 SELECT max ( object_id) from T; SELECT min (object_id) from T; - the equivalence of rewriting, rewriting a small number of complex SQL better performance SET LINESIZE 1000 SET AUTOTRACE ON SELECT max (object_id), min (object_id) from T ; execution plan ----------------------------------------------- --------------------------------------- | Id | Operation | the Name | the Rows | Bytes | Cost (% CPU) | Time | ----------- -------------------------------------------------- ------------------------- | 0 | SELECT STATEMENT | | 1 | 13 | 46 (0)| 00:00:01 | | 1 | SORT AGGREGATE | | 1 | 13 | | | | 2 | INDEX FAST FULL SCAN| PK_OBJECT_ID | 74796 | 949K| 46 (0)| 00:00:01 | -------------------------------------------------------------------------------------- 统计信息 ---------------------------------------------------------- 0 recursive calls 0 db block gets 160 consistent gets 0 physical reads 0 redo size 502 bytes sent via SQL*Net to client 416 bytes received via SQL*Net from client 2 SQL*Net roundtrips to/from client 0 sorts (memory) 0 sorts (disk) 1 rows processed select max, min from (select max(object_id) max from t ) a, (select min(object_id) min from t ) b; 执行计划 --------------------------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | --------------------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 1 | 26 | 4 (0)| 00:00:01 | | 1 | NESTED LOOPS | | 1 | 26 | 4 (0)| 00:00:01 | | 2 | the VIEW | |. 1 | 13 is | 2 (0) | 00:00:01 | |. 3 | AGGREGATE to the SORT | |. 1 | 13 is | | | |. 4 | SCAN FULL the INDEX (MIN / MAX) | PK_OBJECT_ID |. 1 | 13 is | 2 (0) | 00:00:01 | |. 5 | the VIEW | |. 1 | 13 is | 2 (0) | 00:00:01 | |. 6 | AGGREGATE to the SORT | |. 1 | 13 is | | | |. 7 | SCAN FULL the INDEX (MIN / MAX) | PK_OBJECT_ID |. 1 | 13 is | 2 (0) | 00:00:01 | ------------------------ -------------------------------------------------- ------------------- statistics ----------------------------- ----------------------------- 0 recursive calls 0 db block gets 4 consistent gets 0 physical reads 0 redo size 480 bytes sent via SQL*Net to client 416 bytes received via SQL*Net from client 2 SQL*Net roundtrips to/from client 0 sorts (memory) 0 sorts (disk) 1 rows processed
Consider a single combined index Index Example:
The combination of the index index single prefix is consistent drop purge Table T; Create Table T AS SELECT * from dba_objects; Create index idx_object_id ON T (object_id, object_type); SET AUTOTRACE TRACEONLY SET LINESIZE 1000 - the index can be used, because object_id column is the prefix select * from t where object_id = 19 ; execution plan ------------------------------------ -------------------------------------------------- ------- | Id | Operation | the Name | the Rows | Bytes | Cost (% the CPU) | Time | ------------------------ -------------------------------------------------- ------------------- | 0 | the SELECT a STATEMENT | | 1 | 207 | 3 (0) | 00:00:01 | | 1 | TABLE ACCESS BY INDEX the ROWID | T | 1 | 207 | 3 (0) | 00:00:01 | | * 2 | INDEX RANGE SCAN | IDX_OBJECT_ID | 1 | | 2 (0) | 00:00:01 | -------------------------- -------------------------------------------------- ----------------- statistics ------------------------------- --------------------------- 0 recursive This Calls 0 db Block the gets 4 consistent the gets 0 PHYSICAL reads 0 redo size 1392 bytes Sent Via SQL * Net Client to 416 bytes Via the SQL * Net Received from Client 2 the SQL * Net roundtrips to / from Client prefix single combined index inconsistency index drop index idx_object_id; 0 sorts (memory) Sorts 0 (Disk) 1 rows Processed statistics ON t index idx_object_id the Create (object_type, object_id); - The following can not use the index, because the object_id column is a suffix select * from t where object_id = 19 ; execution plan -------------- -------------------------------------------------- ---------- | Id | Operation | the Name | the Rows | Bytes | Cost (% the CPU) | Time | --------------------- -------------------------------------------------- --- | 0 | the SELECT a STATEMENT | | 12 | 2484 | 292 (1) | 00:00:04 | | * 1 | TABLE ACCESS FULL | T | 12 | 2484 | 292 (1) | 00:00:04 | -------------------------------------------------- ------------------------ -------------------------- -------------------------------- 0 recursive This Calls 0 db block gets 1049 consistent gets 0 physical reads 0 redo size 1389 bytes sent via SQL*Net to client 416 bytes received via SQL*Net from client 2 SQL*Net roundtrips to/from client 0 sorts (memory) 0 sorts (disk) 1 rows processed
And in combination query optimization related to:
drop table t purge; create table t as select * from dba_objects; update t set object_id=rownum ; create index idx_id_type on t(object_id,object_type); UPDATE t SET OBJECT_ID=20 WHERE ROWNUM<=26000; UPDATE t SET OBJECT_ID=21 WHERE OBJECT_ID<>20; COMMIT; set linesize 1000 set pagesize 1 alter session set statistics_level=all ; select /*+index(t,idx1_object_id)*/ * from t where object_TYPE='TABLE' AND OBJECT_ID >= 20 AND OBJECT_ID<= 21; select * from table(dbms_xplan.display_cursor(null,null,'allstats last')); -------------------------------------------------------------------------------------------------------- | Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers | -------------------------------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 1 | | 2939 |00:00:00.02 | 1117 | | 1 | TABLE ACCESS BY INDEX ROWID| T | 1 | 3411 | 2939 |00:00:00.02 | 1117 | |* 2 | INDEX RANGE SCAN | IDX_ID_TYPE | 1 | 299 | 2939 |00:00:00.02 | 736 | -------------------------------------------------------------------------------------------------------- 2 - access("OBJECT_ID">=20 AND "OBJECT_TYPE"='TABLE' AND "OBJECT_ID"<=21) filter("OBJECT_TYPE"='TABLE') 已选择25行。 select /*+index(t,idx_id_type)*/ * from t t where object_TYPE='TABLE' AND OBJECT_ID IN (20,21); select * from table(dbms_xplan.display_cursor(null,null,'allstats last')); --------------------------------------------------------------------------------------------------------- | Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers | --------------------------------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 1 | | 2939 |00:00:00.01 | 598 | | 1 | INLIST ITERATOR | | 1 | | 2939 |00:00:00.01 | 598 | | 2 | TABLE ACCESS BY INDEX ROWID| T | 2 | 3411 | 2939 |00:00:00.01 | 598 | | * 3 | INDEX RANGE SCAN | IDX_ID_TYPE | 2 | 1 | 2939 | 00: 00: 00.01 | 217 | -------------------------- -------------------------------------------------- ----------------------------- . 3 - Access ((( "the OBJECT_ID" = OR 20 is "the OBJECT_ID" = 21 is)) the AND " OBJECT_TYPE "= 'TABLE') has selected 25 lines. --- col1, col2, col3 index case, and if not given query condition is COL2, COL3 can only play the role of inspection (still in the optimization) drop the Table t purge; the Create the Table t AS the SELECT * from dba_objects; UPDATE T the SET the oBJECT_ID = 20 is the WHERE rOWNUM <= 26000; the UPDATE T the SET the oBJECT_ID = 21 is the WHERE the oBJECT_ID <> 20 is; the Update T SET object_id = 22 is WHERE rownum <= 10000; a COMMIT; Create index idx_union ON T (object_type, object_id, owner); set autotrace off set linesize 1000 select * from t where object_type='VIEW' and OWNER='LJB'; select * from table(dbms_xplan.display_cursor(null,null,'allstats last')); ------------------------------------------------------------------------------------------------------------ | Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers | Reads | ------------------------------------------------------------------------------------------------------------ | 0 | SELECT STATEMENT | | 1 | | 4 |00:00:00.01 | 24 | 19 | | 1 | TABLE ACCESS BY INDEX ROWID| T | 1 | 9 | 4 |00:00:00.01 | 24 | 19 | |* 2 | INDEX RANGE SCAN | IDX_UNION | 1 | 22 | 4 |00:00:00.01 | 21 | 19 | ------------------------------------------------------------------------------------------------------------ select /*+INDEX(T,idx_union)*/ * from t T where object_type='VIEW' and OBJECT_ID IN (20,21,22) AND OWNER='LJB'; ---------------------------------------------------------------------------------------------------- | Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers | ---------------------------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 1 | | 4 |00:00:00.01 | 13 | | 1 | INLIST ITERATOR | | 1 | | 4 |00:00:00.01 | 13 | | 2 | TABLE ACCESS BY INDEX ROWID| T | 3 | 1 | 4 |00:00:00.01 | 13 | |* 3 | INDEX RANGE SCAN | IDX_UNION | 3 | 1 | 4 |00:00:00.01 | 10 | ---------------------------------------------------------------------------------------------------- 类似 select /*+INDEX(T,idx_union)*/ * from t T where (object_type='VIEW' and OBJECT_ID =20 AND OWNER='LJB') or (object_type='VIEW' and OBJECT_ID =21 AND OWNER='LJB') or (object_type='VIEW' and OBJECT_ID =22 AND OWNER='LJB')