Oracle12c INDEXがUNUSABLEになるとEXTENT,SEGMENTは削除される
概要
ALTER TABLEなどでINDEXがUNUSABLEとなった場合に、EXTENT、SEGMENTは削除されるという事象の検証(というかメモ)です。 OracleMasterの教科書に載っているような話らしいですね。資格は持っていないので知らないです。
Oracle Database 12c Enterprise Edition Release 12.2.0.1.0 - 64bit Production CentOS Linux release 7.3.1611 (Core)
検証
テーブル、インデックスの用意
検証用のテーブルとインデックス、データを用意します。
事前確認
まずは、テーブル、インデックスを作成しただけの状態で、関連ディクショナリを確認します。
ALTER INDEX xxx UNUSABLE
次に、インデックスをUNUSABLEに変更してみます。
SQL> alter index IDX1_TAB_UNUSABLE unusable; Index altered. Elapsed: 00:00:00.06 SQL>
すると、user_extents,user_segmentsからは削除されました。
ALTER INDEX xxx REBUILD
UNUSABLEとなった、インデックスをREBUILDします。
SQL> alter index IDX1_TAB_UNUSABLE rebuild; Index altered. Elapsed: 00:00:00.08 SQL>
extent,segmentも復活しています。
ALTER TABLE xxx MOVE
テーブル圧縮を実行してみます。
SQL> alter table TAB_UNUSABLE move compress for oltp; Table altered. Elapsed: 00:00:00.09 SQL>
テーブルをMOVEすると、インデックスはUNUSABLEになるので、当然と言えば当然なのですが、
やはりextent,segmentからは削除されました。
Centos7にOracle12cのSQL*Loader(12.2.0.1)をインストール
概要
Oracle12cR2のSQL*Loaderをインストールして接続するまでのメモです。
手順
rpmのダウンロード
直リンクだといつしか変わっていたりするので、下記ページで
「oracle client download Linux x86-64」を検索して、
http://www.oracle.com/technetwork/topics/index.html
こちらをダウンロード。
oracle-instantclient12.2-tools-12.2.0.1.0-1.x86_64.rpm
インストール
rpm -ivh oracle-instantclient12.2-tools-12.2.0.1.0-1.x86_64.rpm
ORACLE_HOMEのbinにsqlldrが配置されました。
[standingzzz@apl ~]$ which sqlldr /usr/lib/oracle/12.2/client64/bin/sqlldr [standingzzz@apl ~]$ [standingzzz@apl ~]$ echo $ORACLE_HOME /usr/lib/oracle/12.2/client64
とりあえず接続の確認だけしてみます。
[standingzzz@apl ~]$ sqlldr test01@PDB1 Password: control = SQL*Loader-287: No control file name specified. [standingzzz@apl ~]$
python3.6でOracle12c接続の確認(cx_Oracle)
概要
python3.6でOracle12cへ接続してSQLを実行する際のメモです。
Oracle Database 12c Enterprise Edition Release 12.2.0.1.0 - 64bit Production CentOS Linux release 7.3.1611 (Core) Python 3.6.2
確認
接続情報
DBserver:oracle12c.test port:1521 service_name:orclpdb.test user:test01 password:xxxx
pythonコード
ora_connect.py
import cx_Oracle import sys import os import configparser def connect_Oracle( server, port, user, pswd, service ): try: conn = cx_Oracle.connect( user, pswd, server + ':' + port + '/' + service ) cur = conn.cursor() return ( cur ) except ( cx_Oracle.DatabaseError ) as ex: print ( sys.exc_info()[1] ) raise ex def exec_Oracle_SQL( cur, sql ): try: cur.execute( sql ) rows = cur.fetchall() return ( rows ) except ( cx_Oracle.DatabaseError ) as ex: print ( sys.exc_info()[1] ) raise ex if __name__ == '__main__': cur = connect_Oracle( 'oracle12c.test', '1521', 'test01', 'xxxx', 'orclpdb.test' ) rows = exec_Oracle_SQL( cur, 'select username, user_id from user_users' ) for row in rows: print ( row[0] + ', ', end = "" ) print ( row[1] )
実行結果
[standingzzz@apl common]$ python ora_connect.py TEST01, 108 [standingzzz@apl common]$
CentOS7にOracle12cのInstantClient(12.2.0.1)をインストール
概要
OracleClientをインストールして、SQLPLUSで接続するまでのメモです。
手順
rpmのダウンロード
直リンクだといつしか変わっていたりするので、下記ページで
「oracle client download Linux x86-64」を検索して、
http://www.oracle.com/technetwork/topics/index.html
こちらをダウンロード。
oracle-instantclient12.2-basic-12.2.0.1.0-1.x86_64.rpm oracle-instantclient12.2-sqlplus-12.2.0.1.0-1.x86_64.rpm oracle-instantclient12.2-devel-12.2.0.1.0-1.x86_64.rpm
インストール
rpm -ivh oracle-instantclient12.2-basic-12.2.0.1.0-1.x86_64.rpm rpm -ivh oracle-instantclient12.2-sqlplus-12.2.0.1.0-1.x86_64.rpm rpm -ivh oracle-instantclient12.2-devel-12.2.0.1.0-1.x86_64.rpm
シンボリックリンクの作成
実行ファイルが「sqlplus64」になっているので、このままでも動くのですが、
「sqlplus」で実行したいのでシンボリックリンクを下記のように作成。
ln -s /usr/bin/sqlplus64 /usr/bin/sqlplus
環境変数の設定
sqlplusを動かすには、下記だけあれば十分。
export TNS_ADMIN=/usr/lib/oracle/12.2/client64/network/admin export NLS_LANG=American_Japan.JA16EUCTILDE export LD_LIBRARY_PATH=/usr/lib/oracle/12.2/client64/lib:$LD_LIBRARY_PATH
接続確認
[standingzzz@apl ~]$ sqlplus /nolog SQL*Plus: Release 12.2.0.1.0 Production on Fri Sep 15 16:15:14 2017 Copyright (c) 1982, 2016, Oracle. All rights reserved. SQL> conn test01@PDB1 Enter password: Connected. SQL>
Oracle12c OPTIMIZER_FEATURESによるNOT EXISTS句の実行計画の違いを確認する その2
概要
OPTIMIZER_FEATURESによるNOT EXISTS句の実行計画の違いを確認します。
その1ではSELECT句をcount(*)のみにしたことで、
12.2.0.1のELIMINATE_JOINにより、tab_bのJOINが省略される実行計画となりましたので、
tab_bのカラムをSELECT句に入れたSQLで確認してみます。
検証のベースとなるSQL
select max(a.cdate) , max(b.cdate) from tab_a a left join tab_b b on b.id = a.id and b.cdate > sysdate - 1/24 where not exists ( select 1 from tab_b b2 where b2.id = a.id and mod( b2.id2, 10 ) = 1 and b2.status is null )
Oracle Database 12c Enterprise Edition Release 12.2.0.1.0 - 64bit Production CentOS Linux release 7.3.1611 (Core)
検証
実行計画の確認
12.2.0.1
NAME TYPE VALUE ------------------------------------ ------------ ------------------------------ optimizer_features_enable string 12.2.0.1
MAX(A.CDATE) MAX(B.CDATE) ------------------- ------------------- 2017/09/08 15:02:54 1 row selected. Elapsed: 00:00:04.85 Execution Plan ---------------------------------------------------------- Plan hash value: 2392446093 ---------------------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes |TempSpc| Cost (%CPU)| Time | ---------------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 1 | 73 | | 4799 (2)| 00:00:01 | | 1 | SORT AGGREGATE | | 1 | 73 | | | | |* 2 | HASH JOIN RIGHT OUTER| | 1301K| 90M| | 4799 (2)| 00:00:01 | |* 3 | TABLE ACCESS FULL | TAB_B | 36 | 792 | | 908 (3)| 00:00:01 | |* 4 | HASH JOIN RIGHT ANTI| | 1301K| 63M| 4192K| 3887 (1)| 00:00:01 | |* 5 | TABLE ACCESS FULL | TAB_B | 104K| 2964K| | 895 (1)| 00:00:01 | | 6 | TABLE ACCESS FULL | TAB_A | 1301K| 27M| | 689 (2)| 00:00:01 | ---------------------------------------------------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 2 - access("B"."ID"(+)="A"."ID") 3 - filter("B"."CDATE"(+)>SYSDATE@!-.0416666666666666666666666666666666666667 ) 4 - access("B2"."ID"="A"."ID") 5 - filter("B2"."STATUS" IS NULL AND MOD("B2"."ID2",10)=1) Note ----- - dynamic statistics used: dynamic sampling (level=2) Statistics ---------------------------------------------------------- 11 recursive calls 0 db block gets 8971 consistent gets 0 physical reads 0 redo size 430 bytes sent via SQL*Net to client 500 bytes received via SQL*Net from client 2 SQL*Net roundtrips to/from client 0 sorts (memory) 0 sorts (disk) 1 rows processed
当然ELIMINATE_JOINは出現せず、ごく当たり前の実行計画となりました。
ですが、全てのテーブルをFULLSCANしてHASHJOINするという、
ちょっと乱暴な実行計画になっているので、ヒント句でNestedLoopにします。
1 select /*+ use_nl(a b) */ 2 max(a.cdate) 3 , max(b.cdate) 4 from tab_a a 5 left join tab_b b 6 on b.id = a.id 7 and b.cdate > sysdate - 1/24 8 where not exists ( select /*+ use_nl(b2) */ 9 1 10 from tab_b b2 11 where b2.id = a.id 12 and mod( b2.id2, 10 ) = 1 13 and b2.status is null 14* ) 15 / MAX(A.CDATE) MAX(B.CDATE) ------------------- ------------------- 2017/09/08 15:02:54 1 row selected. Elapsed: 00:00:06.12 Execution Plan ---------------------------------------------------------- Plan hash value: 2565967754 --------------------------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | --------------------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 1 | 73 | 3654K (1)| 00:02:23 | | 1 | SORT AGGREGATE | | 1 | 73 | | | | 2 | NESTED LOOPS ANTI | | 1301K| 90M| 3654K (1)| 00:02:23 | | 3 | NESTED LOOPS OUTER | | 1301K| 54M| 2351K (1)| 00:01:32 | | 4 | TABLE ACCESS FULL | TAB_A | 1301K| 27M| 689 (2)| 00:00:01 | |* 5 | TABLE ACCESS BY INDEX ROWID| TAB_B | 1 | 22 | 2 (0)| 00:00:01 | |* 6 | INDEX UNIQUE SCAN | IDX1_TAB_B | 1 | | 1 (0)| 00:00:01 | |* 7 | TABLE ACCESS BY INDEX ROWID | TAB_B | 1 | 29 | 1 (0)| 00:00:01 | |* 8 | INDEX UNIQUE SCAN | IDX1_TAB_B | 1 | | 1 (0)| 00:00:01 | --------------------------------------------------------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 5 - filter("B"."CDATE"(+)>SYSDATE@!-.0416666666666666666666666666666666666667) 6 - access("B"."ID"(+)="A"."ID") 7 - filter("B2"."STATUS" IS NULL AND MOD("B2"."ID2",10)=1) 8 - access("B2"."ID"="A"."ID") Note ----- - dynamic statistics used: dynamic sampling (level=2) Statistics ---------------------------------------------------------- 11 recursive calls 0 db block gets 117577 consistent gets 2091 physical reads 0 redo size 430 bytes sent via SQL*Net to client 500 bytes received via SQL*Net from client 2 SQL*Net roundtrips to/from client 0 sorts (memory) 0 sorts (disk) 1 rows processed
普通にどちらのtab_bもヒント句が効いて、NestedLoopになりました。
まあこれが効かないようでは困ります。
次は、特に理由はありませんが、ヒント句で結合順がNOT EXISTS句が
先にすることが出来るか確認してみます。
1 select /*+ use_nl(a b) leading(a b2 b) */ 2 max(a.cdate) 3 , max(b.cdate) 4 from tab_a a 5 left join tab_b b 6 on b.id = a.id 7 and b.cdate > sysdate - 1/24 8 where not exists ( select /*+ use_nl(b2) */ 9 1 10 from tab_b b2 11 where b2.id = a.id 12 and mod( b2.id2, 10 ) = 1 13 and b2.status is null 14* ) 15 / MAX(A.CDATE) MAX(B.CDATE) ------------------- ------------------- 2017/09/08 15:02:54 1 row selected. Elapsed: 00:00:01.29 Execution Plan ---------------------------------------------------------- Plan hash value: 2649977225 --------------------------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | --------------------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 1 | 73 | 4703K (1)| 00:03:04 | | 1 | SORT AGGREGATE | | 1 | 73 | | | | 2 | NESTED LOOPS OUTER | | 1301K| 90M| 4703K (1)| 00:03:04 | | 3 | NESTED LOOPS ANTI | | 1301K| 63M| 2351K (1)| 00:01:32 | | 4 | TABLE ACCESS FULL | TAB_A | 1301K| 27M| 689 (2)| 00:00:01 | |* 5 | TABLE ACCESS BY INDEX ROWID| TAB_B | 1 | 29 | 2 (0)| 00:00:01 | |* 6 | INDEX UNIQUE SCAN | IDX1_TAB_B | 1 | | 1 (0)| 00:00:01 | |* 7 | TABLE ACCESS BY INDEX ROWID | TAB_B | 1 | 22 | 2 (0)| 00:00:01 | |* 8 | INDEX UNIQUE SCAN | IDX1_TAB_B | 1 | | 1 (0)| 00:00:01 | --------------------------------------------------------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 5 - filter("B2"."STATUS" IS NULL AND MOD("B2"."ID2",10)=1) 6 - access("B2"."ID"="A"."ID") 7 - filter("B"."CDATE"(+)>SYSDATE@!-.0416666666666666666666666666666666666667) 8 - access("B"."ID"(+)="A"."ID") Note ----- - dynamic statistics used: dynamic sampling (level=2) Statistics ---------------------------------------------------------- 208 recursive calls 6 db block gets 116259 consistent gets 0 physical reads 0 redo size 430 bytes sent via SQL*Net to client 500 bytes received via SQL*Net from client 2 SQL*Net roundtrips to/from client 15 sorts (memory) 0 sorts (disk) 1 rows processed
Predicate Informationを見ると、LEADINGヒント句通りに結合しているのがわかります。
次は、同じSQLで11.2.0.4の実行計画を確認してみます。
alter session set optimizer_features_enable = '11.2.0.4'; NAME TYPE VALUE ------------------------------------ ------------ ------------------------------ optimizer_features_enable string 11.2.0.4
1 select /*+ use_nl(a b) leading(a b2 b) */ 2 max(a.cdate) 3 , max(b.cdate) 4 from tab_a a 5 left join tab_b b 6 on b.id = a.id 7 and b.cdate > sysdate - 1/24 8 where not exists ( select /*+ use_nl(b2) */ 9 1 10 from tab_b b2 11 where b2.id = a.id 12 and mod( b2.id2, 10 ) = 1 13 and b2.status is null 14* ) 15 / MAX(A.CDATE) MAX(B.CDATE) ------------------- ------------------- 2017/09/08 15:02:54 1 row selected. Elapsed: 00:00:01.28 Execution Plan ---------------------------------------------------------- Plan hash value: 2649977225 --------------------------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | --------------------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 1 | 73 | 4703K (1)| 00:03:04 | | 1 | SORT AGGREGATE | | 1 | 73 | | | | 2 | NESTED LOOPS OUTER | | 1301K| 90M| 4703K (1)| 00:03:04 | | 3 | NESTED LOOPS ANTI | | 1301K| 63M| 2351K (1)| 00:01:32 | | 4 | TABLE ACCESS FULL | TAB_A | 1301K| 27M| 689 (2)| 00:00:01 | |* 5 | TABLE ACCESS BY INDEX ROWID| TAB_B | 1 | 29 | 2 (0)| 00:00:01 | |* 6 | INDEX UNIQUE SCAN | IDX1_TAB_B | 1 | | 1 (0)| 00:00:01 | |* 7 | TABLE ACCESS BY INDEX ROWID | TAB_B | 1 | 22 | 2 (0)| 00:00:01 | |* 8 | INDEX UNIQUE SCAN | IDX1_TAB_B | 1 | | 1 (0)| 00:00:01 | --------------------------------------------------------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 5 - filter("B2"."STATUS" IS NULL AND MOD("B2"."ID2",10)=1) 6 - access("B2"."ID"="A"."ID") 7 - filter("B"."CDATE"(+)>SYSDATE@!-.0416666666666666666666666666666666666667) 8 - access("B"."ID"(+)="A"."ID") Note ----- - dynamic statistics used: dynamic sampling (level=2) Statistics ---------------------------------------------------------- 21 recursive calls 4 db block gets 116063 consistent gets 0 physical reads 0 redo size 430 bytes sent via SQL*Net to client 500 bytes received via SQL*Net from client 2 SQL*Net roundtrips to/from client 0 sorts (memory) 0 sorts (disk) 1 rows processed
12.2.0.1と変わらずでした。何かちょっとつまらない確認になりましたが、
変わらないということを確認することも重要ですね。きっと。
Oracle12c OPTIMIZER_FEATURESによるNOT EXISTS句の実行計画の違いを確認する その1
概要
OPTIMIZER_FEATURESによるNOT EXISTS句の実行計画の違いを確認します。
検証のベースとなるSQL
select count(*) from tab_a a left join tab_b b on b.id = a.id and b.cdate > sysdate - 1/24 where not exists ( select 1 from tab_b b2 where b2.id = a.id and mod( b2.id2, 10 ) = 1 and b2.status is null )
Oracle Database 12c Enterprise Edition Release 12.2.0.1.0 - 64bit Production CentOS Linux release 7.3.1611 (Core)
検証
拡張実施前の準備色々
実行計画の確認
12.2.0.1
NAME TYPE VALUE ------------------------------------ ------------ ------------------------------ optimizer_features_enable string 12.2.0.1
COUNT(*) ---------- 900000 1 row selected. Elapsed: 00:00:00.32 Execution Plan ---------------------------------------------------------- Plan hash value: 3207213458 --------------------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes |TempSpc| Cost (%CPU)| Time | --------------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 1 | 42 | | 3332 (1)| 00:00:01 | | 1 | SORT AGGREGATE | | 1 | 42 | | | | |* 2 | HASH JOIN RIGHT ANTI| | 1301K| 52M| 4192K| 3332 (1)| 00:00:01 | |* 3 | TABLE ACCESS FULL | TAB_B | 104K| 2964K| | 895 (1)| 00:00:01 | | 4 | TABLE ACCESS FULL | TAB_A | 1301K| 16M| | 688 (1)| 00:00:01 | --------------------------------------------------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 2 - access("B2"."ID"="A"."ID") 3 - filter("B2"."STATUS" IS NULL AND MOD("B2"."ID2",10)=1) Note ----- - dynamic statistics used: dynamic sampling (level=2) Statistics ---------------------------------------------------------- 48 recursive calls 17 db block gets 5966 consistent gets 0 physical reads 3288 redo size 358 bytes sent via SQL*Net to client 500 bytes received via SQL*Net from client 2 SQL*Net roundtrips to/from client 5 sorts (memory) 0 sorts (disk) 1 rows processed
left joinしているtab_bが実行計画上にいません。どのように処理しているのでしょうか。
続いてoptimizer_features_enableを変更して、リリースバージョンによる違いを確認していきます。
11.2.0.4
alter session set optimizer_features_enable = '11.2.0.4'; NAME TYPE VALUE ------------------------------------ ------------ ------------------------------ optimizer_features_enable string 11.2.0.4
COUNT(*) ---------- 900000 1 row selected. Elapsed: 00:00:01.21 Execution Plan ---------------------------------------------------------- Plan hash value: 4056045473 --------------------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes |TempSpc| Cost (%CPU)| Time | --------------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 1 | 64 | | 8831 (1)| 00:00:01 | | 1 | SORT AGGREGATE | | 1 | 64 | | | | |* 2 | HASH JOIN RIGHT ANTI| | 1301K| 79M| 4192K| 8831 (1)| 00:00:01 | |* 3 | TABLE ACCESS FULL | TAB_B | 104K| 2964K| | 895 (1)| 00:00:01 | |* 4 | HASH JOIN OUTER | | 1301K| 43M| 31M| 4834 (1)| 00:00:01 | | 5 | TABLE ACCESS FULL | TAB_A | 1301K| 16M| | 688 (1)| 00:00:01 | |* 6 | TABLE ACCESS FULL | TAB_B | 1049K| 22M| | 908 (3)| 00:00:01 | --------------------------------------------------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 2 - access("B2"."ID"="A"."ID") 3 - filter("B2"."STATUS" IS NULL AND MOD("B2"."ID2",10)=1) 4 - access("B"."ID"(+)="A"."ID") 6 - filter("B"."CDATE"(+)>SYSDATE@!-.041666666666666666666666666666666666666 7) Note ----- - dynamic statistics used: dynamic sampling (level=2) Statistics ---------------------------------------------------------- 32 recursive calls 10 db block gets 9069 consistent gets 0 physical reads 1036 redo size 358 bytes sent via SQL*Net to client 500 bytes received via SQL*Net from client 2 SQL*Net roundtrips to/from client 0 sorts (memory) 0 sorts (disk) 1 rows processed
11.2.0.4では、まずtab_aとtab_bをOUTER JOINしてから、もう1つのtab_bにANTI結合しています。
うーん、正しいです。非常に正しい。安心しました(?)
もう1つ、12.1.0.2でも確認してみます。
12.1.0.2
alter session set optimizer_features_enable = '12.1.0.2'; NAME TYPE VALUE ------------------------------------ ------------ ------------------------------ optimizer_features_enable string 12.1.0.2
COUNT(*) ---------- 900000 1 row selected. Elapsed: 00:00:00.84 Execution Plan ---------------------------------------------------------- Plan hash value: 4056045473 --------------------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes |TempSpc| Cost (%CPU)| Time | --------------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 1 | 64 | | 8831 (1)| 00:00:01 | | 1 | SORT AGGREGATE | | 1 | 64 | | | | |* 2 | HASH JOIN RIGHT ANTI| | 1301K| 79M| 4192K| 8831 (1)| 00:00:01 | |* 3 | TABLE ACCESS FULL | TAB_B | 104K| 2964K| | 895 (1)| 00:00:01 | |* 4 | HASH JOIN OUTER | | 1301K| 43M| 31M| 4834 (1)| 00:00:01 | | 5 | TABLE ACCESS FULL | TAB_A | 1301K| 16M| | 688 (1)| 00:00:01 | |* 6 | TABLE ACCESS FULL | TAB_B | 1049K| 22M| | 908 (3)| 00:00:01 | --------------------------------------------------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 2 - access("B2"."ID"="A"."ID") 3 - filter("B2"."STATUS" IS NULL AND MOD("B2"."ID2",10)=1) 4 - access("B"."ID"(+)="A"."ID") 6 - filter("B"."CDATE"(+)>SYSDATE@!-.041666666666666666666666666666666666666 7) Note ----- - dynamic statistics used: dynamic sampling (level=2) - this is an adaptive plan Statistics ---------------------------------------------------------- 433 recursive calls 8 db block gets 9697 consistent gets 527 physical reads 0 redo size 358 bytes sent via SQL*Net to client 500 bytes received via SQL*Net from client 2 SQL*Net roundtrips to/from client 16 sorts (memory) 0 sorts (disk) 1 rows processed
これは11.2.0.4と同じです。
もう少しだけ、12.2.0.1でどのように2つのtab_bを処理しているのか確認します。
12.2.0.1 advanced
select * from table(dbms_xplan.display(null, null, 'advanced'));
Plan hash value: 3207213458 --------------------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes |TempSpc| Cost (%CPU)| Time | --------------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 1 | 42 | | 3332 (1)| 00:00:01 | | 1 | SORT AGGREGATE | | 1 | 42 | | | | |* 2 | HASH JOIN RIGHT ANTI| | 1301K| 52M| 4192K| 3332 (1)| 00:00:01 | |* 3 | TABLE ACCESS FULL | TAB_B | 104K| 2964K| | 895 (1)| 00:00:01 | | 4 | TABLE ACCESS FULL | TAB_A | 1301K| 16M| | 688 (1)| 00:00:01 | --------------------------------------------------------------------------------------- Query Block Name / Object Alias (identified by operation id): ------------------------------------------------------------- 1 - SEL$085E11BF 3 - SEL$085E11BF / B2@SEL$3 4 - SEL$085E11BF / A@SEL$1 Outline Data ------------- /*+ BEGIN_OUTLINE_DATA SWAP_JOIN_INPUTS(@"SEL$085E11BF" "B2"@"SEL$3") USE_HASH(@"SEL$085E11BF" "B2"@"SEL$3") LEADING(@"SEL$085E11BF" "A"@"SEL$1" "B2"@"SEL$3") FULL(@"SEL$085E11BF" "B2"@"SEL$3") FULL(@"SEL$085E11BF" "A"@"SEL$1") OUTLINE(@"SEL$1") OUTLINE(@"SEL$2") ANSI_REARCH(@"SEL$1") OUTLINE(@"SEL$8812AA4E") ANSI_REARCH(@"SEL$2") OUTLINE(@"SEL$948754D7") MERGE(@"SEL$8812AA4E" >"SEL$948754D7") OUTLINE(@"SEL$2BFA4EE4") OUTLINE(@"SEL$3") ELIMINATE_JOIN(@"SEL$2BFA4EE4" "B"@"SEL$1") OUTLINE(@"SEL$56824FA9") UNNEST(@"SEL$3") OUTLINE_LEAF(@"SEL$085E11BF") ALL_ROWS DB_VERSION('12.2.0.1') OPTIMIZER_FEATURES_ENABLE('12.2.0.1') IGNORE_OPTIM_EMBEDDED_HINTS END_OUTLINE_DATA */ Predicate Information (identified by operation id): --------------------------------------------------- 2 - access("B2"."ID"="A"."ID") 3 - filter("B2"."STATUS" IS NULL AND MOD("B2"."ID2",10)=1) Column Projection Information (identified by operation id): ----------------------------------------------------------- 1 - (#keys=0) COUNT(*)[22] 2 - (#keys=1; rowset=1019) 3 - (rowset=256) "B2"."ID"[NUMBER,22] 4 - (rowset=1019) "A"."ID"[NUMBER,22] Note ----- - dynamic statistics used: dynamic sampling (level=2)
left joinしているtab_bが出てくるのは、下記のELIMINATE_JOINだけです。
ELIMINATE_JOIN(@"SEL$2BFA4EE4" "B"@"SEL$1")
マニュアルにも記載がありませんので推測になりますが、ELIMINATEは省略する、除くの意味で、
tab_aとtab_bはそれぞれTABLE FULL SCANして結合していますから、
もう1回同じテーブルを結合し直さなくても計算出来ますよ、ということなのでしょう。
何だか賢いですね。その2に続きます。
Oracle12c Centos7 VARCHAR2のカラム長の拡張を検証 Part3.
概要
Part2.の続きです。
拡張データ型カラムの追加、変更、インデックスの作成を検証します。
Oracle Database 12c Enterprise Edition Release 12.1.0.2.0 - 64bit Production CentOS Linux release 7.3.1611 (Core)
検証
拡張データ型カラムの追加、変更
拡張データ型カラムへのインデックス作成
MAX_STRING_SIZEをSTANDARDに変更(ダメ元)
MAX_STRING_SIZEを変更して、拡張データ型カラムを作成することは特に難しいことはないものの、
インデックスはあるサイズになると作成出来なかったり、設定は元に戻せないということもあるので、
本番DBに適用するのは慎重に検討した方が良さそうです。