我有这个非常简单的查询,通过rowid执行过滤和连接。
SELECT *
FROM BOOKING.BOOKING_GRID BG,
BOOKING.BOOKING_STATES BS
WHERE BG.hotel=128
AND BS.ROWID =BG.BOOKINGSTATE;
当我解释计划时,我得到了:
PLAN_TABLE_OUTPUT
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Plan hash value: 1597031677
--------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes |TempSpc| Cost (%CPU)| Time |
--------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 6137K| 1041M| | 1763K (1)| 05:48:27 |
|* 1 | HASH JOIN | | 6137K| 1041M| 538M| 1763K (1)| 05:48:27 |
|* 2 | INDEX UNIQUE SCAN| BOOKING_GRIDPK | 6137K| 468M| | 547K (1)| 01:48:05 |
|* 3 | INDEX RANGE SCAN| BOOKING_GRID_INDEX5 | 6137K| | | 90388 (1)| 00:17:52 |
| 4 | TABLE ACCESS FULL| BOOKING_STATES | 158M| 14G| | 365K (2)| 01:12:14 |
--------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - access("BS".ROWID="BG"."BOOKINGSTATE")
2 - access("BG"."HOTEL"=128)
3 - access("BG"."HOTEL"=128)
BOOKING_GRID的索引是:
BOOKING BOOKING_GRIDPK UNIQUE VALID IOT - TOP N NO NO HOTEL, DAY, BOOKINGSTATE
BOOKING BOOKING_GRID_UNIQ UNIQUE VALID NORMAL N NO NO HOTEL, DAY, BOOKING, VALIDITYSTART
BOOKING BOOKING_GRID_INDEX5 NONUNIQUE VALID NORMAL N NO NO HOTEL, BOOKINGSTATUS, ISDAYUSE, DAY
BOOKING BOOKING_GRID_INDEX7 NONUNIQUE VALID NORMAL N NO NO HOTEL, BOOKING, VALIDITYSTART
BOOKING BOOKING_GRID_INDEX10 NONUNIQUE VALID NORMAL N NO NO HOTEL, ISDAYUSE, BOOKINGSTATUS, DAY
BOOKING_STATES的索引是:
BOOKING BOOKING_STATES_PK UNIQUE VALID NORMAL N NO NO HOTEL, BOOKING, VALIDITYSTART
BOOKING BOOKING_STATES_INDEX2 NONUNIQUE VALID NORMAL N NO NO HOTEL, YIELDROOMTYPE, BOOKEDROOMTYPE, ROOMTYPE
BOOKING BOOKING_STATES_BOOKING NONUNIQUE VALID NORMAL N NO NO HOTEL, BOOKING, BOOKINGSTATUS
BOOKING BOOKING_NOSEGMENT_INDEX NONUNIQUE VALID FUNCTION-BASED NORMAL N NO ENABLED NO SYS_NC00034$ TO_NUMBER(DECODE(TO_CHAR("MARKETSEGMENT"),NULL,DECODE("BOOK",0,NULL,TO_CHAR(DECODE("ISDAYUSE",'N',DECODE("ISSHARED",'N',DECODE("BOOKINGSTATUS",'B',"HOTEL"*10000+LEAST("DEPARTURE","VALIDITYEND"),'I',"HOTEL"*10000+LEAST("DEPARTURE","VALIDITYEND"),'W',"HOTEL"*10000+LEAST("DEPARTURE","VALIDITYEND"))))))))
BOOKING BOOKING_NORATE_CODE_INDEX NONUNIQUE VALID FUNCTION-BASED NORMAL N NO ENABLED NO SYS_NC00033$ TO_NUMBER(DECODE(TO_CHAR("RATECODE"),NULL,DECODE("BOOK",0,NULL,TO_CHAR(DECODE("ISDAYUSE",'N',DECODE("ISSHARED",'N',DECODE("BOOKINGSTATUS",'B',"HOTEL"*10000+LEAST("DEPARTURE","VALIDITYEND"),'I',"HOTEL"*10000+LEAST("DEPARTURE","VALIDITYEND"),'W',"HOTEL"*10000+LEAST("DEPARTURE","VALIDITYEND"))))))))
BOOKING BOOKING_NOBOOKINGTYPE_INDEX NONUNIQUE VALID FUNCTION-BASED NORMAL N NO ENABLED NO SYS_NC00032$ TO_NUMBER(DECODE(TO_CHAR("BOOKINGTYPE"),NULL,DECODE("BOOK",0,NULL,TO_CHAR(DECODE("ISDAYUSE",'N',DECODE("ISSHARED",'N',DECODE("BOOKINGSTATUS",'B',"HOTEL"*10000+LEAST("DEPARTURE","VALIDITYEND"))))))))
BOOKING BOOKING_STATES_BOOKING_TYPE NONUNIQUE VALID NORMAL N NO NO HOTEL, BOOKINGTYPE, ISDAYUSE, BOOKINGSTATUS
BOOKING BOOKING_STATES_CANCEL_INDEX NONUNIQUE VALID FUNCTION-BASED NORMAL N NO ENABLED NO SYS_NC00035$, SYS_NC00036$ DECODE("BOOKINGSTATUS",'c',"HOTEL",'C',"HOTEL")
BOOKING BOOKING_STATES_CANCEL_INDEX NONUNIQUE VALID FUNCTION-BASED NORMAL N NO ENABLED NO SYS_NC00035$, SYS_NC00036$ DECODE("BOOKINGSTATUS",'c',"CANCELREASON",'C',"CANCELREASON")
我不明白两件事:
奇怪的是,当我用hotel = 201运行相同的确切请求时,它完全没问题:
PLAN_TABLE_OUTPUT
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Plan hash value: 4251203092
---------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
---------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 591K| 100M| 643K (1)| 02:07:12 |
| 1 | NESTED LOOPS | | 591K| 100M| 643K (1)| 02:07:12 |
|* 2 | INDEX UNIQUE SCAN | BOOKING_GRIDPK | 591K| 45M| 52686 (1)| 00:10:25 |
|* 3 | INDEX RANGE SCAN | BOOKING_GRID_INDEX5 | 591K| | 8707 (1)| 00:01:44 |
| 4 | TABLE ACCESS BY USER ROWID| BOOKING_STATES | 1 | 98 | 1 (0)| 00:00:01 |
---------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - access("BG"."HOTEL"=201)
3 - access("BG"."HOTEL"=201)
有关于那里发生了什么的任何想法吗?
谢谢,
雷诺
答案 0 :(得分:1)
不同执行路径的原因是因为Oracle认为大约有600万行,其中hotel = 128但只有591,000行,其中hotel = 201。在更大的中间集的情况下,Oracle选择了嵌套循环的散列连接。
我没有得到的是:
AND BS.ROWID =BG.BOOKINGSTATE;
您将Oracle格式的ROWID存储在名为BOOKINGSTATE ???
的列中好的,鉴于您确认BOOKINGSTATE确实包含Oracle ROWID,这就是为什么我说你得到的是HASH JOIN而不是NESTED LOOP加入:
首先,当Oracle读取一行时,它不是一次只读取一行,而是一次读取一行。因此,要使用TABLE ACCESS BY USER ROWID查找来执行NESTED LOOP连接,它将在BOOKING_GRID中找到一行,然后读取具有该ROWID的BOOKING_STATES中的行的块。问题是,如果稍后在另一行中有一个已经读过的块中的rowid,它将重新读取该块(当然,它可以被缓存)以获得另一行。有点像“打开街区,排成一排,关闭包装盒......然后再打开同一个包装盒,再拿一排,关上包装盒,继续往下一个方框”
另一方面,您的哈希联接是: - 对较小集合中的行进行排序(在本例中为BOOKING_GRID中的行,其中hotel = 128),将它们放入内存中 - 全表扫描BOOKING_STATES - 这里是踢球者 - 使用多块读取。它一次读取多个块并处理块中的所有行,而不需要以后需要重新读取它。这就像“打开盒子,处理盒子里的所有行,然后关闭盒子。”
(有关上述结果http://docs.oracle.com/cd/B28359_01/server.111/b28274/optimops.htm的详细信息,请参阅以下部分:
顺便说一下,它有点好奇它正在进行“访问(”BG“。”HOTEL“= 128)”使用两个索引两步 - 显示BOOKING_GRIDPK和BOOKING_GRID_INDEX5索引?您要求两个表中的所有列,但计划从不接触BOOKING_GRID表。)