另外请了解位图联结索引,此类问题的最佳实践。
这是一个星型联结的例子,sales为事实表,其它为维度表。where条件全部都作用在维度表上面。
sh@ prod> select quantity_sold , amount_sold from sales s join products p using ( prod_id )
2 join times using ( time_id ) join customers c using ( cust_id )
3 where week_ending_day = '29-nov-2008'
4 and prod_name = '1.44mb external 3.5'' diskette'
5 and cust_year_of_birth = 1965 ;
no rows selected
execution plan
----------------------------------------------------------
plan hash value: 3891315047
--------------------------------------------------------------------------------------------------------------------------
| id | operation | name | rows | bytes | cost (%cpu)| time | pstart| pstop |
--------------------------------------------------------------------------------------------------------------------------
| 0 | select statement | | 1 | 80 | 30 (0)| 00:00:01 | | |
| 1 | nested loops | | | | | | | |
| 2 | nested loops | | 1 | 80 | 30 (0)| 00:00:01 | | |
| 3 | nested loops | | 4 | 284 | 26 (0)| 00:00:01 | | |
| 4 | merge join cartesian | | 1 | 46 | 21 (0)| 00:00:01 | | |
|* 5 | table access full | times | 1 | 16 | 18 (0)| 00:00:01 | | |
| 6 | buffer sort | | 1 | 30 | 3 (0)| 00:00:01 | | |
|* 7 | table access full | products | 1 | 30 | 3 (0)| 00:00:01 | | |
| 8 | table access by global index rowid| sales | 9 | 225 | 5 (0)| 00:00:01 | rowid | rowid |
|* 9 | index range scan | sales_concat_idx | 9 | | 2 (0)| 00:00:01 | | |
|* 10 | index unique scan | customers_pk | 1 | | 0 (0)| 00:00:01 | | |
|* 11 | table access by index rowid | customers | 1 | 9 | 1 (0)| 00:00:01 | | |
--------------------------------------------------------------------------------------------------------------------------
predicate information (identified by operation id):
---------------------------------------------------
5 - filter("times"."week_ending_day"=to_date(' 2008-11-29 00:00:00', 'syyyy-mm-dd hh24:mi:ss'))
7 - filter("p"."prod_name"='1.44mb external 3.5'' diskette')
9 - access("s"."prod_id"="p"."prod_id" and "s"."time_id"="times"."time_id")
10 - access("s"."cust_id"="c"."cust_id")
11 - filter("c"."cust_year_of_birth"=1965)
statistics
----------------------------------------------------------
1 recursive calls
0 db block gets
56 consistent gets
0 physical reads
0 redo size
414 bytes sent via sql*net to client
512 bytes received via sql*net from client
1 sql*net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
0rows processed
执行计划中用到了笛卡尔联结。
其实上面的查询等效于下面的(连执行计划都是一样的):
sh@ prod> select quantity_sold , amount_sold from sales s
2 where s.prod_id in ( select prod_id from products where prod_name = '1.44mb external 3.5" diskette' )
3 and s.time_id in ( select time_id from times where week_ending_day = '29-nov-2008' )
4 and s.cust_id in ( select cust_id from customers where cust_year_of_birth = 1965 ) ;
no rows selected
execution plan
----------------------------------------------------------
plan hash value: 3891315047
--------------------------------------------------------------------------------------------------------------------------
| id | operation | name | rows | bytes | cost (%cpu)| time | pstart| pstop |
--------------------------------------------------------------------------------------------------------------------------
| 0 | select statement | | 1 | 80 | 30 (0)| 00:00:01 | | |
| 1 | nested loops | | | | | | | |
| 2 | nested loops | | 1 | 80 | 30 (0)| 00:00:01 | | |
| 3 | nested loops | | 4 | 284 | 26 (0)| 00:00:01 | | |
| 4 | merge join cartesian | | 1 | 46 | 21 (0)| 00:00:01 | | |
|* 5 | table access full | times | 1 | 16 | 18 (0)| 00:00:01 | | |
| 6 | buffer sort | | 1 | 30 | 3 (0)| 00:00:01 | | |
|* 7 | table access full | products | 1 | 30 | 3 (0)| 00:00:01 | | |
| 8 | table access by global index rowid| sales | 9 | 225 | 5 (0)| 00:00:01 | rowid | rowid |
|* 9 | index range scan | sales_concat_idx | 9 | | 2 (0)| 00:00:01 | | |
|* 10 | index unique scan | customers_pk | 1 | | 0 (0)| 00:00:01 | | |
|* 11 | table access by index rowid | customers | 1 | 9 | 1 (0)| 00:00:01 | | |
--------------------------------------------------------------------------------------------------------------------------
predicate information (identified by operation id):
---------------------------------------------------
5 - filter("week_ending_day"=to_date(' 2008-11-29 00:00:00', 'syyyy-mm-dd hh24:mi:ss'))
7 - filter("prod_name"='1.44mb external 3.5" diskette')
9 - access("s"."prod_id"="prod_id" and "s"."time_id"="time_id")
10 - access("s"."cust_id"="cust_id")
11 - filter("cust_year_of_birth"=1965)
statistics
----------------------------------------------------------
1 recursive calls
0 db block gets
56 consistent gets
0 physical reads
0 redo size
414 bytes sent via sql*net to client
512 bytes received via sql*net from client
1 sql*net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
0 rows processed
使能星型联结转换(注意,星型联结转换默认不是使能的)
sh@ prod> alter session set star_transformation_enabled = true ;
session altered.
再看两个表的执行计划,其实还是一样的,只不过更多的使用了位图合并。这需要在事实表的每个外键上添加位图索引。
这种叫做星型转换,一般用在数据仓库中。
sh@ prod> select quantity_sold , amount_sold from sales s
2 where s.prod_id in ( select prod_id from products where prod_name = '1.44mb external 3.5" diskette' )
3 and s.time_id in ( select time_id from times where week_ending_day = '29-nov-2008' )
4 and s.cust_id in ( select cust_id from customers where cust_year_of_birth = 1965 ) ;
no rows selected
execution plan
----------------------------------------------------------
plan hash value: 3061144765
-----------------------------------------------------------------------------------------------------------------------
| id | operation | name | rows | bytes | cost (%cpu)| time | pstart| pstop |
-----------------------------------------------------------------------------------------------------------------------
| 0 | select statement | | 1 | 34 | 53 (0)| 00:00:01 | | |
| 1 | nested loops | | | | | | | |
| 2 | nested loops | | 1 | 34 | 32 (0)| 00:00:01 | | |
| 3 | partition range subquery | | 8 | 218 | 23 (0)| 00:00:01 |key(sq)|key(sq)|
| 4 | table access by local index rowid| sales | 8 | 218 | 23 (0)| 00:00:01 |key(sq)|key(sq)|
| 5 | bitmap conversion to rowids | | | | | | | |
| 6 | bitmap and | | | | | | | |
| 7 | bitmap merge | | | | | | | |
| 8 | bitmap key iteration | | | | | | | |
| 9 | buffer sort | | | | | | | |
|* 10 | table access full | times | 1 | 16 | 18 (0)| 00:00:01 | | |
|* 11 | bitmap index range scan | sales_time_bix | | | | |key(sq)|key(sq)|
| 12 | bitmap merge | | | | | | | |
| 13 | bitmap key iteration | | | | | | | |
| 14 | buffer sort | | | | | | | |
|* 15 | table access full | products | 1 | 30 | 3 (0)| 00:00:01 | | |
|* 16 | bitmap index range scan | sales_prod_bix | | | | |key(sq)|key(sq)|
|* 17 | index unique scan | customers_pk | 1 | | 0 (0)| 00:00:01 | | |
|* 18 | table access by index rowid | customers | 1 | 9 | 1 (0)| 00:00:01 | | |
-----------------------------------------------------------------------------------------------------------------------
predicate information (identified by operation id):
---------------------------------------------------
10 - filter("week_ending_day"=to_date(' 2008-11-29 00:00:00', 'syyyy-mm-dd hh24:mi:ss'))
11 - access("s"."time_id"="time_id")
15 - filter("prod_name"='1.44mb external 3.5" diskette')
16 - access("s"."prod_id"="prod_id")
17 - access("s"."cust_id"="cust_id")
18 - filter("cust_year_of_birth"=1965)
note
-----
- star transformation used for this statement
statistics
----------------------------------------------------------
5 recursive calls
0 db block gets
56 consistent gets
0 physical reads
0 redo size
414 bytes sent via sql*net to client
512 bytes received via sql*net from client
1 sql*net roundtrips to/from client
1 sorts (memory)
0 sorts (disk)
0 rows processed
sh@ prod> select quantity_sold , amount_sold from sales s join products p using ( prod_id )
2 join times using ( time_id ) join customers c using ( cust_id )
3 where week_ending_day = '29-nov-2008'
4 and prod_name = '1.44mb external 3.5'' diskette'
5 and cust_year_of_birth = 1965 ;
no rows selected
execution plan
----------------------------------------------------------
plan hash value: 3061144765
-----------------------------------------------------------------------------------------------------------------------
| id | operation | name | rows | bytes | cost (%cpu)| time | pstart| pstop |
-----------------------------------------------------------------------------------------------------------------------
| 0 | select statement | | 1 | 34 | 53 (0)| 00:00:01 | | |
| 1 | nested loops | | | | | | | |
| 2 | nested loops | | 1 | 34 | 32 (0)| 00:00:01 | | |
| 3 | partition range subquery | | 8 | 218 | 23 (0)| 00:00:01 |key(sq)|key(sq)|
| 4 | table access by local index rowid| sales | 8 | 218 | 23 (0)| 00:00:01 |key(sq)|key(sq)|
| 5 | bitmap conversion to rowids | | | | | | | |
| 6 | bitmap and | | | | | | | |
| 7 | bitmap merge | | | | | | | |
| 8 | bitmap key iteration | | | | | | | |
| 9 | buffer sort | | | | | | | |
|* 10 | table access full | times | 1 | 16 | 18 (0)| 00:00:01 | | |
|* 11 | bitmap index range scan | sales_time_bix | | | | |key(sq)|key(sq)|
| 12 | bitmap merge | | | | | | | |
| 13 | bitmap key iteration | | | | | | | |
| 14 | buffer sort | | | | | | | |
|* 15 | table access full | products | 1 | 30 | 3 (0)| 00:00:01 | | |
|* 16 | bitmap index range scan | sales_prod_bix | | | | |key(sq)|key(sq)|
|* 17 | index unique scan | customers_pk | 1 | | 0 (0)| 00:00:01 | | |
|* 18 | table access by index rowid | customers | 1 | 9 | 1 (0)| 00:00:01 | | |
-----------------------------------------------------------------------------------------------------------------------
predicate information (identified by operation id):
---------------------------------------------------
10 - filter("times"."week_ending_day"=to_date(' 2008-11-29 00:00:00', 'syyyy-mm-dd hh24:mi:ss'))
11 - access("s"."time_id"="times"."time_id")
15 - filter("p"."prod_name"='1.44mb external 3.5'' diskette')
16 - access("s"."prod_id"="p"."prod_id")
17 - access("s"."cust_id"="c"."cust_id")
18 - filter("c"."cust_year_of_birth"=1965)
note
-----
- star transformation used for this statement
statistics
----------------------------------------------------------
4 recursive calls
0 db block gets
56 consistent gets
0 physical reads
0 redo size
414 bytes sent via sql*net to client
512 bytes received via sql*net from client
1 sql*net roundtrips to/from client
1 sorts (memory)
0 sorts (disk)
0 rows processed