[20181219]不能使用USE_CONCAT優化例子.txt
[20181219]不能使用USE_CONCAT優化例子.txt
--//連結http://www.itpub.net/thread-2107240-2-1.html,http://www.itpub.net/thread-2107231-2-1.html的討論.
SQL_ID 6qsvy74cbrm6x, child number 0
-------------------------------------
SELECT /*+ gather_plan_statistics USE_CONCAT */ * FROM ljapay
WHERE incomeno IN (SELECT contno FROM
lccont WHERE prtno = '1300000000617430')
OR otherno = '1300000000617430'
Plan hash value: 2966270370
------------------------------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows |E-Bytes| Cost (%CPU)| E-Time | A-Rows | A-Time | Buffers |
------------------------------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | | | 549 (100)| | 0 |00:00:00.33 | 233K|
|* 1 | FILTER | | 1 | | | | | 0 |00:00:00.33 | 233K|
| 2 | TABLE ACCESS FULL | LJAPAY | 1 | 67404 | 13M| 549 (1)| 00:00:07 | 67404 |00:00:00.04 | 2015 |
|* 3 | TABLE ACCESS BY INDEX ROWID| LCCONT | 67376 | 1 | 37 | 3 (0)| 00:00:01 | 0 |00:00:00.25 | 231K|
|* 4 | INDEX UNIQUE SCAN | PK_LCCONT | 67376 | 1 | | 2 (0)| 00:00:01 | 63370 |00:00:00.12 | 168K|
------------------------------------------------------------------------------------------------------------------------------------
--//加入USE_CONCAT並沒有用,走的是filter,更要命的是id=3,4的starts=67376,大部分邏輯讀都在這裡.
--//作者執行的是修改,我換成了select語句.
--//我自己寫一個測試例子驗證看看.
1.環境:
SCOTT@book> @ ver1
PORT_STRING VERSION BANNER
------------------------------ -------------- --------------------------------------------------------------------------------
x86_64/Linux 2.4.xx 11.2.0.4.0 Oracle Database 11g Enterprise Edition Release 11.2.0.4.0 - 64bit Production
create table t1 as select rownum id1 ,rownum id2 ,lpad('x',100,'x') name from dual connect by level<=6000;
create table t2 as select rownum id1 ,rownum id2 ,lpad('x',100,'x') name from dual connect by level<=6000;
create index i_t1_id1 on t1(id1);
create index i_t1_id2 on t1(id2);
create index i_t2_id1 on t2(id1);
--//分析略.
2.測試:
SCOTT@book> alter session set statistics_level = all;
Session altered.
SCOTT@book> select * from t1 where t1.id1 in (select t2.id1 from t2 where t2.id1=11 ) or (t1.id2=10 );
ID1 ID2 NAME
---------- ---------- ----------------------------------------------------------------------------------------------------
10 10 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
11 11 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
SCOTT@book> @ dpc '' ''
PLAN_TABLE_OUTPUT
-------------------------------------
SQL_ID gz5pqkg6svm7k, child number 0
-------------------------------------
select * from t1 where t1.id1 in (select t2.id1 from t2 where
t2.id1=11 ) or (t1.id2=10 )
Plan hash value: 1962644737
-------------------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows |E-Bytes| Cost (%CPU)| E-Time | A-Rows | A-Time | Buffers |
-------------------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | | | 30 (100)| | 2 |00:00:00.01 | 102 |
|* 1 | FILTER | | 1 | | | | | 2 |00:00:00.01 | 102 |
| 2 | TABLE ACCESS FULL| T1 | 1 | 6000 | 638K| 30 (0)| 00:00:01 | 6000 |00:00:00.01 | 100 |
|* 3 | FILTER | | 5999 | | | | | 1 |00:00:00.01 | 2 |
|* 4 | INDEX RANGE SCAN| I_T2_ID1 | 1 | 1 | 4 | 1 (0)| 00:00:01 | 1 |00:00:00.01 | 2 |
-------------------------------------------------------------------------------------------------------------------------
Query Block Name / Object Alias (identified by operation id):
-------------------------------------------------------------
1 - SEL$1
2 - SEL$1 / T1@SEL$1
3 - SEL$2
4 - SEL$2 / T2@SEL$2
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter(("T1"."ID2"=10 OR IS NOT NULL))
3 - filter(11=:B1)
4 - access("T2"."ID1"=:B1)
32 rows selected.
--//我的版本與作者看到的不同,仔細看id=4的starts就明白了,實際上這裡應該迴圈5999次.
--//我的版本11.2.0.4(沒有打任何補丁),而他使用版本是11.2.0.4.180717.
--//也就是我使用的版本最後的buffers計算錯誤.
--//加入提示:
select /*+ USE_CONCAT */ * from t1 where t1.id1 in (select t2.id1 from t2 where t2.id1=11 ) or (t1.id2=10 );
--//執行效果一樣.使用如下提示:
select /*+ USE_CONCAT(@"SEL$1" 8 OR_PREDICATES(1)) */ * from t1 where t1.id1 in (select t2.id1 from t2 where t2.id1=11 ) or (t1.id2=10 );
--//執行計劃如下:
SCOTT@book> @ dpc '' ''
PLAN_TABLE_OUTPUT
-------------------------------------
SQL_ID 9m6dksysdc87a, child number 0
-------------------------------------
select /*+ USE_CONCAT(@"SEL$1" 8 OR_PREDICATES(1)) */ * from t1 where
t1.id1 in (select t2.id1 from t2 where t2.id1=11 ) or (t1.id2=10 )
Plan hash value: 1154250921
-----------------------------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows |E-Bytes| Cost (%CPU)| E-Time | A-Rows | A-Time | Buffers |
-----------------------------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | | | 33 (100)| | 2 |00:00:00.01 | 105 |
| 1 | CONCATENATION | | 1 | | | | | 2 |00:00:00.01 | 105 |
| 2 | TABLE ACCESS BY INDEX ROWID| T1 | 1 | 1 | 109 | 2 (0)| 00:00:01 | 1 |00:00:00.01 | 4 |
|* 3 | INDEX RANGE SCAN | I_T1_ID2 | 1 | 1 | | 1 (0)| 00:00:01 | 1 |00:00:00.01 | 3 |
|* 4 | FILTER | | 1 | | | | | 1 |00:00:00.01 | 101 |
|* 5 | TABLE ACCESS FULL | T1 | 1 | 5999 | 638K| 30 (0)| 00:00:01 | 5999 |00:00:00.01 | 99 |
|* 6 | FILTER | | 5999 | | | | | 1 |00:00:00.01 | 2 |
|* 7 | INDEX RANGE SCAN | I_T2_ID1 | 1 | 1 | 4 | 1 (0)| 00:00:01 | 1 |00:00:00.01 | 2 |
-----------------------------------------------------------------------------------------------------------------------------------
Query Block Name / Object Alias (identified by operation id):
-------------------------------------------------------------
1 - SEL$1
2 - SEL$1_1 / T1@SEL$1
3 - SEL$1_1 / T1@SEL$1
5 - SEL$1_2 / T1@SEL$1_2
6 - SEL$2
7 - SEL$2 / T2@SEL$2
Predicate Information (identified by operation id):
---------------------------------------------------
3 - access("T1"."ID2"=10)
4 - filter( IS NOT NULL)
5 - filter(LNNVL("T1"."ID2"=10))
6 - filter(11=:B1)
7 - access("T2"."ID1"=:B1)
--//提示起作用.但是id=4,走的是filter,一樣效率低下.改寫如下:
select /*+ USE_CONCAT(@"SEL$1" 8 OR_PREDICATES(1)) */ * from t1 where t1.id1 in (select /*+ unnest */ t2.id1 from t2 where t2.id1=11 ) or (t1.id2=10 );
--//也是一樣unnest沒用.看了開發版的連結:http://www.itpub.net/thread-2107231-1-1.html,改用OR_EXPANSION問題依舊.
select /*+ OR_EXPAND */ * from t1 where t1.id1 in (select /*+ unnest */ t2.id1 from t2 where t2.id1=11 ) or (t1.id2=10 );
--//這樣使用union all:
select * from t1 where t1.id1 in (select /*+ unnest */ t2.id1 from t2 where t2.id1=11 ) and lnnvl(t1.id2=10)
union all
select * from t1 where (t1.id2=10 );
--//或者使用union:
select * from t1 where t1.id1 in (select /*+ unnest */ t2.id1 from t2 where t2.id1=11 )
union
select * from t1 where (t1.id2=10 );
--//感覺使用union all 效果更好.貼出使用union all的執行計劃:
SQL_ID 3619bvczapunb, child number 0
-------------------------------------
select * from t1 where t1.id1 in (select /*+ unnest */ t2.id1 from t2
where t2.id1=11 ) and lnnvl(t1.id2=10) union all select * from t1 where
(t1.id2=10 )
Plan hash value: 3919113390
------------------------------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows |E-Bytes| Cost (%CPU)| E-Time | A-Rows | A-Time | Buffers |
------------------------------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | | | 5 (100)| | 2 |00:00:00.01 | 9 |
| 1 | UNION-ALL | | 1 | | | | | 2 |00:00:00.01 | 9 |
| 2 | NESTED LOOPS SEMI | | 1 | 1 | 113 | 3 (0)| 00:00:01 | 1 |00:00:00.01 | 6 |
|* 3 | TABLE ACCESS BY INDEX ROWID| T1 | 1 | 1 | 109 | 2 (0)| 00:00:01 | 1 |00:00:00.01 | 4 |
|* 4 | INDEX RANGE SCAN | I_T1_ID1 | 1 | 1 | | 1 (0)| 00:00:01 | 1 |00:00:00.01 | 3 |
|* 5 | INDEX RANGE SCAN | I_T2_ID1 | 1 | 1 | 4 | 1 (0)| 00:00:01 | 1 |00:00:00.01 | 2 |
| 6 | TABLE ACCESS BY INDEX ROWID | T1 | 1 | 1 | 109 | 2 (0)| 00:00:01 | 1 |00:00:00.01 | 3 |
|* 7 | INDEX RANGE SCAN | I_T1_ID2 | 1 | 1 | | 1 (0)| 00:00:01 | 1 |00:00:00.01 | 2 |
------------------------------------------------------------------------------------------------------------------------------------
Query Block Name / Object Alias (identified by operation id):
-------------------------------------------------------------
1 - SET$1
2 - SEL$5DA710D3
3 - SEL$5DA710D3 / T1@SEL$1
4 - SEL$5DA710D3 / T1@SEL$1
5 - SEL$5DA710D3 / T2@SEL$2
6 - SEL$3 / T1@SEL$3
7 - SEL$3 / T1@SEL$3
Predicate Information (identified by operation id):
---------------------------------------------------
3 - filter(LNNVL("T1"."ID2"=10))
4 - access("T1"."ID1"=11)
5 - access("T2"."ID1"=11)
filter("T1"."ID1"="T2"."ID1")
7 - access("T1"."ID2"=10)
Column Projection Information (identified by operation id):
-----------------------------------------------------------
1 - STRDEF[22], STRDEF[22], STRDEF[100]
2 - "T1"."ID1"[NUMBER,22], "T1"."ID2"[NUMBER,22], "T1"."NAME"[VARCHAR2,100]
3 - "T1"."ID1"[NUMBER,22], "T1"."ID2"[NUMBER,22], "T1"."NAME"[VARCHAR2,100]
4 - "T1".ROWID[ROWID,10], "T1"."ID1"[NUMBER,22]
6 - "T1"."ID1"[NUMBER,22], "T1"."ID2"[NUMBER,22], "T1"."NAME"[VARCHAR2,100]
7 - "T1".ROWID[ROWID,10], "T1"."ID2"[NUMBER,22]
3.繼續:
--//不過對方執行的是修改操作,使用union all或者union,不能基於結果集合的修改.
--//會報錯誤 ORA-01732: data manipulation operation not legal on this view.
--//關於結果集修改看連結:http://blog.itpub.net/267265/viewspace-2139049/
--// 修改條件使用主鍵或者rowid就ok了.貼出使用rowid的改寫:
update t1 set name='zzz' where
rowid in
(
select rowid from t1 where t1.id1 in (select /*+ unnest */ t2.id1 from t2 where t2.id1=11 ) and lnnvl(t1.id2=10)
union all
select rowid from t1 where (t1.id2=10 )
);
SCOTT@book> @ dpc '' ''
PLAN_TABLE_OUTPUT
-------------------------------------
SQL_ID g6608508whaar, child number 0
-------------------------------------
update t1 set name='zzz' where rowid in ( select rowid from t1 where
t1.id1 in (select /*+ unnest */ t2.id1 from t2 where t2.id1=11 ) and
lnnvl(t1.id2=10) union all select rowid from t1 where (t1.id2=10 ) )
Plan hash value: 3348292872
-------------------------------------------------------------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows |E-Bytes| Cost (%CPU)| E-Time | A-Rows | A-Time | Buffers | OMem | 1Mem | Used-Mem |
-------------------------------------------------------------------------------------------------------------------------------------------------------------------
| 0 | UPDATE STATEMENT | | 1 | | | 6 (100)| | 0 |00:00:00.01 | 10 | | | |
| 1 | UPDATE | T1 | 1 | | | | | 0 |00:00:00.01 | 10 | | | |
| 2 | NESTED LOOPS | | 1 | 120 | 14520 | 6 (0)| 00:00:01 | 2 |00:00:00.01 | 8 | | | |
| 3 | VIEW | VW_NSO_1 | 1 | 2 | 24 | 4 (0)| 00:00:01 | 2 |00:00:00.01 | 7 | | | |
| 4 | SORT UNIQUE | | 1 | 2 | 40 | 4 (0)| 00:00:01 | 2 |00:00:00.01 | 7 | 73728 | 73728 | |
| 5 | UNION-ALL | | 1 | | | | | 2 |00:00:00.01 | 7 | | | |
| 6 | NESTED LOOPS SEMI | | 1 | 1 | 24 | 3 (0)| 00:00:01 | 1 |00:00:00.01 | 5 | | | |
|* 7 | TABLE ACCESS BY INDEX ROWID| T1 | 1 | 1 | 20 | 2 (0)| 00:00:01 | 1 |00:00:00.01 | 3 | | | |
|* 8 | INDEX RANGE SCAN | I_T1_ID1 | 1 | 1 | | 1 (0)| 00:00:01 | 1 |00:00:00.01 | 2 | | | |
|* 9 | INDEX RANGE SCAN | I_T2_ID1 | 1 | 1 | 4 | 1 (0)| 00:00:01 | 1 |00:00:00.01 | 2 | | | |
|* 10 | INDEX RANGE SCAN | I_T1_ID2 | 1 | 1 | 16 | 1 (0)| 00:00:01 | 1 |00:00:00.01 | 2 | | | |
| 11 | TABLE ACCESS BY USER ROWID | T1 | 2 | 60 | 6540 | 1 (0)| 00:00:01 | 2 |00:00:00.01 | 1 | | | |
-------------------------------------------------------------------------------------------------------------------------------------------------------------------
Query Block Name / Object Alias (identified by operation id):
-------------------------------------------------------------
1 - SEL$9C09E64D
3 - SET$FCA7A018 / VW_NSO_1@SEL$9C09E64D
4 - SET$FCA7A018
6 - SEL$5DA710D3
7 - SEL$5DA710D3 / T1@SEL$1
8 - SEL$5DA710D3 / T1@SEL$1
9 - SEL$5DA710D3 / T2@SEL$2
10 - SEL$3 / T1@SEL$3
11 - SEL$9C09E64D / T1@UPD$1
Predicate Information (identified by operation id):
---------------------------------------------------
7 - filter(LNNVL("T1"."ID2"=10))
8 - access("T1"."ID1"=11)
9 - access("T2"."ID1"=11)
filter("T1"."ID1"="T2"."ID1")
10 - access("T1"."ID2"=10)
--//id=4 SORT UNIQUE,依舊需要去除重複的記錄.另外連結也提供了使用merge的例子,我個人很少使用它.貼出對方改寫的merge的例子:
MERGE INTO ljapay t1
USING (SELECT a.payno, a.currency
FROM ljapay a JOIN lccont b ON a.incomeno = b.contno
WHERE b.prtno = 'Q99180000000110'
UNION
SELECT a.payno, a.currency
FROM ljapay a
WHERE otherno = 'Q99180000000110') t2
ON (t1.payno = t2.payno AND t1.currency = t2.currency)
WHEN MATCHED
THEN
UPDATE SET
t1.Operstate = '0'
,t1.modifydate = DATE '2018-12-17'
,t1.modifytime = '16:20:44'
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/267265/viewspace-2285693/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- [20190524]使用use_concat or_expand提示優化.txt優化
- [20181219]script使用小技巧.txt
- 【丁原 】優化小例子優化
- [20170328]使用with優化1例.txt優化
- [20181219]記錄自己工作中的錯誤.txt
- SEO優化-robots.txt解讀優化
- [20181220]使用提示OR_EXPAND優化.txt優化
- [20181119]使用sql profile優化問題.txtSQL優化
- [20210408]max優化.txt優化
- [20170601]distinct的優化.txt優化
- 舉個例子看如何做MySQL 核心深度優化MySql優化
- 記一次優化ansible inventory的小例子優化
- php mysql 一個查詢優化的簡單例子PHPMySql優化單例
- [20170708]tmux script例子.txtUX
- [20170912]sql injection例子.txtSQL
- [20170104]一條sql優化.txtSQL優化
- MySQL 5.7 優化不能只看執行計劃MySql優化
- oracle 使用leading, use_nl, rownum調優例子Oracle
- [20160919]sql注入例子.txtSQL
- 如何針對SEO優化您的WordPress Robots.txt優化
- [20231226]vim Align外掛使用例子.txt
- [轉]oracle 使用leading, use_nl, rownum調優例子Oracle
- SQL優化案例-使用with as優化Subquery Unnesting(七)SQL優化
- Oracle優化案例-使用with as優化Subquery Unnesting(七)Oracle優化
- 使用explain優化sqlAI優化SQL
- EntityFramework使用及優化Framework優化
- [20131217]pivot應用例子.txt
- 20181219網路管理
- [20190624]12c group by優化 .txt優化
- [20220428]優化的困惑12.txt優化
- [20210203]max優化的困惑.txt優化
- [20201224]sql優化困惑.txtSQL優化
- [20131204]sql語句優化.txtSQL優化
- [20151221]sql語句優化.txtSQL優化
- 使用優化實用工具來優化SQL Server效能優化SQLServer
- websocket使用小例子Web
- Grails 使用MySQL例子AIMySql
- at new 的使用例子