一条SQL语句变得巨慢的原因及其解决方法


景象:一条SQL蓦地运行的特殊慢 。

select uidTable.column_value, first_name||' '
||last_name, company, job_title, upper(member_level), 
upper(service_value)
from (select * from table(select cast(multiset
(select b from bbb)as Taaa) from dual)) uidTable,member
where uidTable.column_value = member.login_id(+) 
and member.site='alibaba' and member.site='test';

出错缘由:消费者添加了一个条件member.site=test,造成衔接的顺序 变迁了,原来的驱动表是uidTable(最多1024条记录),现在变成了member表做驱动(600W条) 。所以这条语句变的巨慢 。

然而既然是外衔接,为何衔接的顺序会转变呢?由于外衔接的衔接顺序不是由COST决定的,而是由衔接的条件决定的 。发现执行 方案如下:

-------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost |
--------------------------------------------------------
| 0 | SELECT STATEMENT | | 1018 | 72278 | 8155 |
| 1 | NESTED LOOPS | | 1018 | 72278 | 8155 |
| 2 | VIEW | | 4072 | 69224 | 11 |
| 3 | COLLECTION ITERATOR SUBQUERY FETCH| | | | |
| 4 | TABLE ACCESS FULL | DUAL | 4072 | | 11 |
| 5 | TABLE ACCESS FULL | BBB | 41 | 287 | 2 |
| 6 | TABLE ACCESS BY INDEX ROWID | MEMBER | 1 | 54 | 2 |
|* 7 | INDEX UNIQUE SCAN | MEMBER_SITE_LID_PK | 4 | | 1 |
-------------------------------------------------

为何 根本就没有执行外衔接呢?问题出在member.site='test'这个条件上,由于对外衔接的表加了条件,造成外衔接失效 。改为member.site(+)='test'后,问题彻底解决 。

---------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost |
-----------------------------------------------------
| 0 | SELECT STATEMENT | | 1018 | 72278 | 8155 |
| 1 | NESTED LOOPS | | 1018 | 72278 | 8155 |
| 2 | VIEW | | 4072 | 69224 | 11 |
| 3 | COLLECTION ITERATOR SUBQUERY FETCH| | | | |
| 4 | TABLE ACCESS FULL | DUAL | 4072 | | 11 |
| 5 | TABLE ACCESS FULL | BBB | 41 | 287 | 2 |
| 6 | TABLE ACCESS BY INDEX ROWID | MEMBER | 1 | 54 | 2 |
|* 7 | INDEX UNIQUE SCAN | MEMBER_SITE_LID_PK | 4 | | 1 |
-----------------------------------------------------------