标量子查询优化
当使用另外一个SELECT 语句来产生结果中的一列的值的时候,这个查询必须只能返回一行一列的值。这种类型的子查询被称为标量子查询
在某些情况下可以进行优化以减少标量子查询的重复执行,但更糟糕的场景是每一行都需要标量子查询的执行。
explain plan for SELECT B.EMP_NO,
B.CUST_NO,
B.CUST_NAME,
A.CARD_NO,
A.TRANS_AMT,
A.TRANS_ATTR,
/*(0 ?? 1 鲁盲 2 鲁盲?禄?4 ??)*/
A.TRANS_TIME,
A.SEQNO,
A.OLD_TRANSDATE
FROM (SELECT * FROM DWF.F_EVT_REAL_JOURLIST WHERE TRANS_TYPE = '00') A
LEFT JOIN (SELECT AGMT_ID,
CUST_MAGR EMP_NO,
CUST_NO,
(SELECT DISTINCT PTY_NAME
FROM DWF.F_PTY_TABLE
WHERE PTY_ID = A.CUST_NO
AND START_DT <= TO_DATE('2012-09-30', 'YYYY-MM-DD')
AND END_DT > TO_DATE('2012-09-30', 'YYYY-MM-DD')) CUST_NAME
FROM DWF.F_AGT_CADB_BOOK_H A
WHERE START_DT <= TO_DATE('2012-09-30', 'YYYY-MM-DD')
AND END_DT > TO_DATE('2012-09-30', 'YYYY-MM-DD')) B ON A.CARD_NO =
B.AGMT_ID;
--220109
SELECT AGMT_ID,
CUST_MAGR EMP_NO,
CUST_NO,
(SELECT DISTINCT PTY_NAME
FROM DWF.F_PTY_TABLE
WHERE PTY_ID = A.CUST_NO
AND START_DT <= TO_DATE('2012-09-30', 'YYYY-MM-DD')
AND END_DT > TO_DATE('2012-09-30', 'YYYY-MM-DD')) CUST_NAME
FROM DWF.F_AGT_CADB_BOOK_H A
WHERE START_DT <= TO_DATE('2012-09-30', 'YYYY-MM-DD')
AND END_DT > TO_DATE('2012-09-30', 'YYYY-MM-DD')
查询返回了204947条记录
###########################################################################################################################
Plan hash value: 579615344
---------------------------------------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers | Reads | OMem | 1Mem | Used-Mem |
---------------------------------------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | | 220K|00:00:12.12 | 781K| 280K| | | |
| 1 | SORT UNIQUE | |155K | 1 | 155K|00:00:06.52 | 501K| 2882 | 2048 | 2048 | 2048 (0)|
|* 2 | TABLE ACCESS BY INDEX ROWID | F_PTY_TABLE |155K | 1 | 155K|00:00:05.41 | 501K| 2882 | | | |
|* 3 | INDEX RANGE SCAN | SYS_C0052731 |155K | 1 | 188K|00:00:04.17 | 313K| 448 | | | |
|* 4 | HASH JOIN OUTER | | 1 | 1399K| 220K|00:00:12.12 | 781K| 280K| 20M| 2674K| 25M (0)|
|* 5 | TABLE ACCESS FULL | F_EVT_REAL_JOURLIST | 1 | 145K| 220K|00:00:00.08 | 7904 | 7900 | | | |
| 6 | VIEW | | 1 | 3929K| 204K|00:00:11.54 | 773K| 272K| | | |
|* 7 | TABLE ACCESS FULL | F_AGT_CADB_BOOK_H | 1 | 3929K| 204K|00:00:04.68 | 272K| 270K| | | |
--------------------------------------------------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - filter("END_DT">TO_DATE(' 2012-09-30 00:00:00', 'syyyy-mm-dd hh24:mi:ss'))
3 - access("PTY_ID"=:B1 AND "START_DT"<=TO_DATE(' 2012-09-30 00:00:00', 'syyyy-mm-dd hh24:mi:ss'))
filter("START_DT"<=TO_DATE(' 2012-09-30 00:00:00', 'syyyy-mm-dd hh24:mi:ss'))
4 - access("F_EVT_REAL_JOURLIST"."CARD_NO"="B"."AGMT_ID")
5 - filter("TRANS_TYPE"='00')
7 - filter(("START_DT"<=TO_DATE(' 2012-09-30 00:00:00', 'syyyy-mm-dd hh24:mi:ss') AND "END_DT">TO_DATE(' 2012-09-30 00:00:00',
'syyyy-mm-dd hh24:mi:ss')))
43 rows selected.
此时对F_PTY_TABLE索引扫描了155K次,回表了155K次 这种效率能高吗?
改写为关联
###########################################################################################
SELECT b.emp_no,
b.cust_no,
b.cust_name,
a.card_no,
a.trans_amt,
a.trans_attr,
a.trans_time,
a.seqno,
a.old_transdate
FROM (SELECT * FROM dwf.f_evt_real_jourlist WHERE trans_type = '00') a
LEFT JOIN (SELECT agmt_id,
cust_magr emp_no,
cust_no,
c_n.pty_name AS cust_name
FROM dwf.f_agt_cadb_book_h a
LEFT JOIN (SELECT pty_name, pty_id
FROM dwf.f_pty_table
WHERE start_dt <=
to_date('2012-09-30', 'YYYY-MM-DD')
AND end_dt > to_date('2012-09-30', 'YYYY-MM-DD')
GROUP BY pty_name, pty_id) c_n
ON c_n.pty_id = a.cust_no
WHERE start_dt <= to_date('2012-09-30', 'YYYY-MM-DD')
AND end_dt > to_date('2012-09-30', 'YYYY-MM-DD')) b
ON a.card_no = b.agmt_id;
这里巧妙的运用了group by 来去除重复数据,像伟大的教主致敬.