このコーナーでは、『津島博士のパフォーマンス講座』の記事に寄せられたご質問に、津島博士が直接お答えしていきます。
(質問方法は、こちらのページをご参照ください)

ご質問をお寄せいただいたページ一覧
【第2回】RAC(Real Application Clusters)の時のバッチ処理について(記事はこちら
【第10回】パーティションについて(記事はこちら
【第11回】良いSQLについて(2)(記事はこちら
【第13回】キャッシュ周りについて (記事はこちら
【第18回】ロックについて (記事はこちら
【第20回】パラレル実行について (記事はこちら
【第21回】索引について (記事はこちら
【第28回】表圧縮とLOBデータ型について (記事はこちら
【第32回】SQL統計と実行計画の出力について(記事はこちら
【第38回】SQLチューニングについて (記事はこちら
【第41回】SQL*Plusについて (記事はこちら
【第43回】パーティションについて(3) (記事はこちら
【第55回】オプティマイザ・ヒントについて(記事はこちら

 

ご質問 - 第2回 RAC(Real Application Clusters)の時のバッチ処理について

 

■ご質問【vol.1】

津島博士のパフォーマンス講座  第2回 RAC(Real Application Clusters)の時のバッチ処理について

>===================================================================
>【抜粋】
> 格納先テーブルへの処理が挿入だけであれば自動セグメント領域管理を使用することで
> フリーリスト/フリーリストグループ管理をしてくれるのでキャッシュ・フュージョン
> が発生しないことも知っておいて下さい。
>===================================================================

上記内容について質問がございます。

なぜ、テーブルへの処理が挿入だけの場合、キャッシュフュージョンが発生しないのでしょうか。
自動セグメント領域管理を使用することでブロックの競合を抑止出来ることは理解出来るのですが、
キャッシュフュージョンの抑止との関連性まで読み解くことが出来ませんでした。

 

■津島博士からの回答

質問ありがとうございます。回答いたします。

キャッシュ・フュージョンは、インスタンス間で同一ブロックを更新するときなどに発生しますが、
フリーリストとフリーリストグループを自動的に管理する自動セグメント領域管理(ASSM)を使用することで、
同一ブロックへの挿入が回避できるため発生しなくなります。ただし、索引が存在すると発生する場合があります。

<フリーリストとフリーリストグループの補足>
挿入処理は、先頭のブロックから順番に格納していく必要はありませんので、各サーバープロセスが別々のブロックに挿入した方が効果的です。このように処理を行うために、フリーリストとフリーリストグループがあります。ただし、索引は、値によって格納するブロックが決まりますので、このような処理はできません。

フリーリストは、挿入が可能なブリーブロック(PCTFREE以上の空き領域があるブロックなど)のリストになりますので、この値以内のサーバープロセスが同時に挿入すると、異なるフリーブロックが使用され競合を回避することができます。フリーリストグループは、RACのインスタンスごとに別々のフリーリストを割り振ることができる機能になりますので、インスタンスごとに同一ブロックに挿入することを回避でき、キャッシュ・フュージョンが発生しなくなります。ただし、各インスタンスごとにフリーブロックが管理されますので、領域の使用効率が低下する場合がありますが、フリーリストグループの変更は再作成の必要があり管理が大変です。そのため、現在では、このフリーブロック管理を自動的に行ってくれるASSMの方が推奨になります。

 

■ご質問【vol.2】

(vol.1と同じ方からの返信です。)

質問事項への回答、誠に有難うございます。

回答いただきました内容について1点だけ確認させてください。

フリーリストは、挿入が可能なブリーブロック(PCTFREE以上の
空き領域があるブロックなど)のリストになりますので、
この値以内のサーバープロセスが同時に挿入すると、
異なるフリーブロックが使用され競合を回避することができます。
上記の「この値以内のサーバープロセス」における「この値」は
何を指していますでしょうか。

フリーリストグループは、RACのインスタンスごとに別々の
フリーリストを割り振ることができる機能になりますので、
インスタンスごとに同一ブロックに挿入することを回避でき、
キャッシュ・フュージョンが発生しなくなります。
RACインスタンス毎に異なるフリーリストが割当てられるため、
INSERT処理におけるキャッシュ・フュージョンが回避出来る旨、
理解出来ました。有難うございます。

以上となります。
————————–
以上、2点どうぞ宜しくお願い致します。

—————————-

 

■津島博士からの回答

質問ありがとうございます。回答いたします。

フリーリストは、挿入が可能なブリーブロック(PCTFREE以上の
空き領域があるブロックなど)のリストになりますので、
この値以内のサーバープロセスが同時に挿入すると、
異なるフリーブロックが使用され競合を回避することができます。
> 上記の「この値以内のサーバープロセス」における「この値」は
> 何を指していますでしょうか。
FREELISTS記憶域パラメータに指定した値になります。

説明が分かりづらくて申し訳ございませんでした。

 

津島博士

 

ご質問 - 【第10回】パーティションについて

 

■ご質問

第10回 パーティションについて

>ローカル非同一キー索引を使用する場合はそうはいきません。この場合は、以下の例のようにパーティション・キーを一意索引キーのサブセットにすることで使用できます。
>これで同一キーが別パーティションに格納されることはないので一意性が確保されます。知っておくと便利かと思います。

>SQL> CREATE TABLE tab1 ( … ) PARTITION BY RANGE (c2) … ;
>SQL> CREATE UNIQUE INDEX tab1_pk ON tab1 (c1,c2) LOCAL;
>SQL> ALTER TABLE tab1 ADD CONSTRAINT tab1_pk PRIMARY KEY (c1,c2) USING INDEX tab1_pk;

この部分が分かりません。
この例だと、本来の主キー項目は c1 のみで、ローカルインデックスとするために本来不要な c2 を加えて(c1,c2)でユニークインデックスを作っているのだと推測します。
(もともとc1、c2が主キーならば 「ローカル同一キー索引」となるはずなので)

しかしこれでは (C1 – 123, C2 – 00)、 (C1 – 123 、 C2 -01) のようなレコードは C1、C2 の組み合わせでは一意となりません。
実際にテストテーブルを作ってみたところ2レコード登録できてしまいました(別パーティションに)

【質問1】
>これで同一キーが別パーティションに格納されることはないので一意性が確保されます

とはどのような意味でしょうか?
【質問2】
c1 のみで一意としたい場合に、ローカル索引で主キーを作る方法はあるでしょうか?

 

■津島博士からの回答

質問ありがとうございます。回答いたします。

ご指摘の通り、この例では列’c1’だけで一意にならないので、そうしたい場合は主キーを’c1’にすることになります。ただし、ローカル索引を主キー(一意索引)にするには、パーティションキー列を含めないと作成できないので、ローカル索引にすることはできません。そのため、そのようなことを意識してパーティションキー列を決めないと、主キーをローカル索引にはできないということです。説明が少し分かりにくいようですので、内容を変更しようと思います。

>【質問1】
>これで同一キーが別パーティションに格納されることはないので一意性が確保されます
>とはどのような意味でしょうか?
ローカル索引を一意にするためには、同一索引キーを別パーティションに格納しないようにする必要がありますので、そのためには索引キー列にパーティションキー列を含める必要があるということです(含んでいないと’ORA-14039’エラーになります)。

> 【質問2】
> c1 のみで一意としたい場合に、ローカル索引で主キーを作る方法はあるでしょうか?
上記でも説明していますが、パーティションキー列がc1以外であれば作成することはできません。つまり、索引のメンテナンス性を重視するのであれば、主キーになる列でパーティション化する方が良いということです。

 

津島博士

 

ご質問 - 【第11回】良いSQLについて(2)

 

■ご質問

https://blogs.oracle.com/otnjp/tsushima-hakushi-11

DBMS_PARALLEL_EXECUTE でPARALLELでSELECTするときのFETCH 方法を追記していただけないでしょうか?
ALTER SESSION FORCE PARALLEL DML PARALLEL xx ;
ALTER SESSION FORCE PARALLEL QUERY PARALLEL xx ;
があった方が良いでしょうか?

 

■津島博士からの回答

質問ありがとうございます。回答いたします。

https://blogs.oracle.com/otnjp/tsushima-hakushi-11
>DBMS_PARALLEL_EXECUTE でPARALLELでSELECTするときのFETCH 方法を追記していただけないでしょうか?
DBMS_PARALLEL_EXECUTEは、PL/SQLプロシージャやDMLなどのデータが返らない処理を、
分割した単位でパラレル実行(複数セッションで実行)するパッケージになります。
そのため、SELECTとFETCHだけを行うような処理を、このパッケージでパラレル化することはできませんので、
使用例のtest_batchプロシージャのように、SELECT後にDMLを行うようなプロシージャを作成して行うようにお願いします。

>ALTER SESSION FORCE PARALLEL DML PARALLEL xx ;
>ALTER SESSION FORCE PARALLEL QUERY PARALLEL xx ;
>があった方が良いでしょうか?
パラレル問合せ、パラレルDMLに対するパラレル指定になりますので、DBMS_PARALLEL_EXECUTEには関係ありません。
DBMS_PARALLEL_EXECUTEでパラレル度を指定するのは以下のPARALLEL_LEVELパラメータになります。
 

 DBMS_PARALLEL_EXECUTE.RUN_TASK('test_task',l_sql_stmt,DBMS_SQL.NATIVE,PARALLEL_LEVEL=>xx); 
        

 

津島博士

 

ご質問 - 【第13回】キャッシュ周りについて

 

■ご質問 【vol.1】

津島博士のパフォーマンス講座 – 第13回 キャッシュ周りについて(https://blogs.oracle.com/otnjp/tsushima-hakushi-13)を拝見させていただきました。

この中にある図でデータベースバッファキャッシュがありますが、
データベースバッファキャッシュという大きな領域に各バッファプールが入っているように見受けられます。
SGAからデータベースバッファキャッシュという領域を確保して、
各プールの領域はデータベースバッファキャッシュから確保するのでしょうか。

 

■津島博士からの回答

質問ありがとうございます。回答いたします。

データベースバッファキャッシュは、すべてのバッファプールを指しますので、このような図にしておりますが、
データベースバッファキャッシュという領域がある訳ではなく、それぞれのプールを以下の初期化パラメータで指定して
SGA(System Global Area)から確保されます。

・DB_CACHE_SIZEパラメータ(DEFAULTプール)
・DB_KEEP_CACHE_SIZEパラメータ(KEEPプール)
・DB_RECYCLE_CACHE_SIZEパラメータ(RECYCLEプール)
・DB_nK_CACHE_SIZEパラメータ(nは2、4、8、16、32で、各ブロックサイズのプール)

ただし、自動メモリ管理(または自動共有メモリ管理)でサイズが自動調整されるのは、DEFAULTプールだけになります。

 

■ご質問 【vol.2】

(vol.1と同じ方からの返信です。)

ご回答ありがとうございます。
回答してもらえると思ってなかったので、
本当に感謝してます。

いただいた回答は私の認識通りでした。
が、それを説明しても納得してくれない者が一人おります。

そればかりか、db_cache_sizeは全ての(標準、キープ、リサイクル、nkバッファなどの)合計だと言ってきます。

呆れてますが、この人に分かってもらうのに適したマニュアル、または津島様の執筆された記事などはありますでしょうか。

何度も質問してすみません。

ただ、間違えた解釈を持った方は正したいので質問させてください。
お忙しくところ、誠に申し訳ありません。

 

■津島博士からの回答

質問ありがとうございます。回答いたします。

複数バッファプールを使用しない場合は、DEFAULTプールだけのためバッファキャッシュと言っていることが多いので、 勘違いされている方もいるかもしれません。もう少し明確に説明するように気を付けたいと思います。

Oracle® Databaseパフォーマンス・チューニング・ガイド (12.2, 18c, 19c)の
以下に記述されている内容では納得していただけませんでしょうか。

・「13.3 複数バッファ・プールの構成」
デフォルト・バッファ・プールのサイズは、DB_CACHE_SIZE初期化パラメータによって決まります。

・「13.3.6 KEEPプールの構成」
KEEPプールのメモリーは、デフォルト・プールのサブセットではありません。

・「13.3.7 RECYCLEプールの構成」
RECYCLEプールのメモリーは、デフォルト・プールのサブセットではありません。

津島様が記載されている「津島博士のパフォーマンス講座」を拝見いたしました、xxと申します。コラムに記載されているLong Tables Scanについて質問があります。
可能であればご回答いただければと思います。

Long Tables Scanの回数を動的パフォーマンスビューV$SESSTAT の"table scans (long tables)" から取得できるかと思います。
こちらで取得される値はフルスキャンを行った際にLong Tablesと判断されたTablesへのフルスキャンの回数でインデックススキャンでLong Tablesと判断される巨大なIndexファイルをスキャンした場合は含まれないという事でしょうか?

■津島博士からの回答

質問ありがとうございます。回答いたします。

「大きなテーブル」、「小さなテーブル」の判断は、全表スキャンの時に バッファ・キャッシュに載せるかどうかを決定するために行います。 索引スキャンは、常にランダム・リードでバッファ・キャッシュ経由になりますので、この判断は行われません。 そのため、"table scans (long tables)"や"table scans (short tables)"がカウントされるのは全表スキャンだけになります。参考までにダイレクトリードされた全表スキャンは"table scans (direct read)"がカウントされます。

<補足として>
索引スキャンのINDEX FAST FULL SCANのときは、索引をマルチ・ブロック・リードでフル・スキャンしますが、 表に比べてサイズが小さいため上記のような判断はせずに
バッファ・キャッシュに格納します(例えば、起動直後などに索引の全てのブロックをバッファ・キャッシュに載せたい場合などに使用します)。
例外として、INDEX FAST FULL SCANがパラレル実行されると、ダイレクト・リードになりバッファ・キャッシュには載せなくなることはありますが、この統計が更新されることはありません。 (このINDEX FAST FULL SCANは、必要な列が索引にすべて
含まれているときだけ実行される機能ですので、表はアクセスされません)。

コラムを読んで頂いてありがとうございます。
他に聞きたいことなどあれば、できるだけ回答しようと思いますので問合せして下さい。
もしかするとコラムの中で回答させていただくかもしれませんが、宜しくお願い致します。

 

津島博士

 

ご質問 - 【第18回】ロックについて

 

■ご質問

「第18回 ロックについて」の中で記載されている1つ目の表におきまして、 SELECT…FOR UPDATE…がRSだと表記されておりますが、正しくはRXではないでしょうか?

■津島博士からの回答

質問ありがとうございます。回答いたします。

SELECT…FOR UPDATEのTMロックモードは、以下のバージョンからRX(行排他モード) に変更になっておりますので、内容を修正したいと思います。
・Oracle Database 9iR2(9.2.0.6以上)br ・Oracle Database 10gR1(10.1.0.4以上)br
修正は、第18回の「(3)TXエンキューとTMエンキュー」の最後(表の後)に、以下の内容を追加することにいたします。

SELECT…FOR UPDATE…は、Oracle Database 9iR2(9.2.0.6以上)及びOracle Database 10gR1(10.1.0.4以上)からRX(行排他モード) に変更になっております。

 

津島博士

 

ご質問 - 【第20回】パラレル実行について

 

■ご質問

第20回パラレル実行について内にて、(3)同時実行の所で、
初期化パラメータPARALLEL_ADAPTIVE_MULTI_USERについての説明が書かれています。
この初期化パラメータはデフォルトでTRUEであり、
説明を読む限り、同時実行制御についてはOracleに任せたほうがよいと思っていました。

ところが、先日発表されたホワイトペーパー
OracleDatabase12cでのパラレル実行の基本
を読むと、26ページの推奨値の表では、この値はFALSEになっていました。
これは、何故なのでしょうか。

■津島博士からの回答

システムに負荷がかかり過ぎないということではPARALLEL_ADAPTIVE_MULTI_USERは良い機能ですが、
以下のような問題点によって使用するのが難しいところがあります。

  • それぞれのSQLで最適なパラレル度を設定する必要がある。
  • SQLによってはパラレル度を下げることで処理時間が大幅に伸びる可能性がある。
  • パラレル度を下げるSQLを決められない。

そのため、現在ではより効果的な同時実行制御を行うことができるように、
自動並列度(自動DOP)、ステートメント・キューイング、リソース・マネージャを使用した同時実行制御を推奨しております。
これは、第40回で説明したようにOracleDatabase12cからの拡張によって、より効果的に動作するようになっています。

以上です。

 

津島博士

 

ご質問 - 【第21回】索引について

 

■ご質問

1.索引の決め方
(1)・頻繁にソートされている列にて

“だだし、NULLが存在する列のBツリー索引では効果がありません。(使用されません)”

 

【質問1】つまり、NULLが存在する列については索引に設定しても使用されない意味でしょうか。
クエリの結果にNULLを求めた場合の効果がないことでしょうか。Bツリー以外の索引にした方がいいことでしょうか。

“複数列索引ではすべての列値がNULLの場合のみ含まれないようになります”

【質問2】何が含まれないでしょうか。

■津島博士からの回答

【質問1の回答】

ソート処理にも索引を使用することができますが、NULLが存在する列のBツリー索引ではソートに使用することができないというこ とで す。これは NULLが存在して いない場合でもNOT NULLが定義されていないと使用されません。

例えば、列c1に索引が存在する場合に、以下のSQLで索引を使用してソート処理をすることができますが、列c1にNOT NULLが定義されていないとソート処理にBツリー索引を使用することができません。
select * from tab order by c1

以下のようにNULL以外にするとBツリー索引は使用されます。
select * from tab where c1 is not null order by c1

このようなNULLが存在するBツリー索引でもWHERE句の条件では使用されますので、間違いないようにしてください。ただし、IS NULLの条件では使用されません。

【質問2の回答】

NULLはBツリー索引にキーとして格納されませんが、複数列索引のときはすべての列がNULLの場合だけ格納されなくなります。
つまり、一つの列だけがNULLでも格納されるということです。

 

津島博士

 

ご質問 - 【第28回】表圧縮とLOBデータ型について

 

■ご質問

第28回 表圧縮とLOBデータ型についてですが、オブジェクトを圧縮することでエクステントサイズが小さくなることはわかりました。
(エクステントサイズが小さくなることで、I/Oが減少することもわかりました)

さて。
圧縮されたブロックを読み込んだ後の、バッファキャッシュの状態について教えて下さい。
圧縮されたブロックを読み込んだ場合、バッファキャッシュ上には圧縮されたままのブロックデータがキャッシュされるのでしょうか?
それとも、バッフャキャッシュ上には、既に展開された状態のブロックがキャッシュされるのでしょうか?

(圧縮が展開されるタイミングが知りたいです。
 もし圧縮されたままバッファキャッシュ上にキャッシュされるのであれば、バッファキャッシュの領域も削減されるので、必然的にキャッシュヒット率も向上するのでは?と思った次第です)

以上、よろしくお願い致します。

■津島博士からの回答

質問ありがとうございます。回答いたします。

質問ありがとうございます。

>圧縮されたブロックを読み込んだ後の、バッファキャッシュの状態について教えて下さい。
>圧縮されたブロックを読み込んだ場合、バッファキャッシュ上には圧縮されたままのブロックデータがキャッシュされるのでしょうか?
>それとも、バッフャキャッシュ上には、既に展開された状態のブロックがキャッシュされるのでしょうか?
圧縮機能は、Oracleブロックに格納するとき(OLTP圧縮はしきい値を超えたとき)に圧縮する機能になりますが、その Oracleブロックを非圧縮にすることはありませ んので、バッファキャッシュ上にも同 じOracleブロックが格納されます(圧 縮されているときには圧 縮状態で格納されます)。
そのため、圧縮が展開されるのは、Oracleブロックからデータを取り出すときになります。

>(圧縮が展開されるタイミングが知りたいです。
> もし圧縮されたままバッファキャッシュ上にキャッシュされるのであれば、
> バッファキャッシュの領域も削減されるので、必然的にキャッシュヒット率も向上するのでは?と思った次第です)
その通りでございます。圧縮にはキャッシュヒット率が向上するというメリットもあります。

 

津島博士

 

ご質問 - 【第32回】SQL統計と実行計画の出力について

 

■ご質問

津島博士の記事について 第32回 SQL統計と実行計画の出力について

現場において、SQLパフォーマンスチューニングに取り組んでおります。
SQL改善案の改善効果を評価するにあたりトレース情報を取得し比較検証を試みております。
SQLの実行時間を評価するにあたり、トレース情報で取得される「Elapsed Time」と、
SET TIMINGコマンドで取得できる「経過時間」とではどのような違いがあるのでしょうか。

また、SQLトレース情報を見る場合は
「total」行の各数値を見ればよい理解ですが
認識合っていますでしょうか。

以上、ご教示のほど宜しくお願い致します。

 

■津島博士からの回答

質問ありがとうございます。回答いたします。

>現場において、SQLパフォーマンスチューニングに取り組んでおります。
>SQL改善案の改善効果を評価するにあたりトレース情報を取得し比較検証を試みております。
頑張ってください。
扱って欲しい内容などがりましたら、お知らせしてください。できるだけ対応するようにいたします。

>SQLの実行時間を評価するにあたり、トレース情報で取得される「Elapsed Time」と、
>SET TIMINGコマンドで取得できる「経過時間」とではどのような違いがあるのでしょうか。
それぞれの時間は、以下のようになります。
・SQLトレースの「Elapsed Time」は、Oracle Database内で処理された時間です。
・SQL*PlusのSET TIMINGコマンドは、SQL*Plusが処理完了した時間になります。取得結果を画面出力していると、その時間も含まれます。取得結果を画面出力しなくない場合は、第41回、第62回に方法を載せていますので参照してください。

>また、SQLトレース情報を見る場合は
>「total」行の各数値を見ればよい理解ですが
>認識合っていますでしょうか。
SQLの実行全体に対しては「total」を見るのが正しいです。

 

津島博士

 

ご質問 - 【第38回】SQLチューニングについて

 

■ご質問

第38回 SQLチューニングについて(https://blogs.oracle.com/otnjp/tsushima-hakushi-38)において「2. SQL計画ベースラインについて」の紹介がありました。

これは、アウトラインを使用したプラン・スタビリティに似ていると感じました。
outln を使用した場合は、他のインスタンスで作成したアウトラインでも、
outln スキーマのデータを exp して、ターゲットのインスタンスで imp することで、
異なるインスタンス間で実行計画を移すことができました。
(旧KROWN#23739の手順です)

このアウトラインのように、SQL計画ベースラインを異なるインスタンスに移して使用することは出来るのでしょうか?

■津島博士からの回答

質問ありがとうございます。回答いたします。

行うことが可能です。詳細は以下のドキュメントを参照してください。

・Oracle Databaseパフォーマンス・チューニング・ガイド11gリリース2 (11.2)
15.7 SQL計画ベースラインのインポートとエクスポート

・Oracle Database SQLチューニング・ガイド12cリリース1(12.1)
23.4.3 ステージング表からの計画のロード

 

津島博士

 

ご質問 - 【第41回】SQL*Plusについて

 

■ご質問

第41回 SQL*Plusについて(https://blogs.oracle.com/otnjp/tsushima-hakushi-41)において「1. SQL*Plusのチューニングについて-(2)データの出力」の箇所にて、

SET AUTOTRACE TRACEONLY

とすることで、

データ出力を抑止してSQL文の実行を行うことができます。
これでSQL文統計は出力されますが、
スプール出力するためのデータ編集は行わないので、CPUオーバーヘッドが削減されます。

とあります。
しかしこれだと、データを Fetch するフェーズが無くなってしまうので、
Fetch 時間を含めたテストを行いたい場合、正確な時間が測れないのではないでしょうか?

■津島博士からの回答

質問ありがとうございます。回答いたします。

SET AUTOTRACE
TRACEONLYの動作は、データをFetchするが出力しないという動作になりますので、Fetchするフェーズがなくなるということはありません
(できるだけSQL*Plus側の負荷を削減するような動作になります)。

<補足として>

SQL*PlusではデータをFetchしないように設定することはできません。そのため、大量データを検索する場合はここがオーバーヘッドになってしまうので、パラレル実行を行っても効果があまり出ない場合があるので注意が必要です。

 

津島博士

 

ご質問 - 【第43回】パーティションについて(3)

 

■ご質問

第43回 パーティションについて(3)(https://blogs.oracle.com/otnjp/tsushima-hakushi-43)ですが、
「1. グローバル索引-(2)索引の自動更新」
の箇所にて、UPDATE INDEXES句について、以下のように記述されています。

パーティションのデータが別のパーティションに移動する操作(COALESCE、MERGE、SPLIT)については、
ローカル索引でもそのパーティションがUNUSABLEになります。
そのため、Oracle Database 10gからローカル索引もメンテナンスされるように、
以下のUPDATE INDEXES句(索引の自動更新)が追加されているので、基本はこれを使用するようにしてください
(ローカル索引については、内部的に再構築が実行されます)。

しかし、しばちょう先生の記事
第27回 パーティション表の管理~ILMにおける表データの圧縮と索引の再構成~(https://blogs.oracle.com/otnjp/shibacho-027)では、以下のように記述されています。

ちなみに、ALTER TABLE MOVE文に「UPDATE INDEXES」句を付け加えることで、
表セグメントの移動後に索引のRebuildを自動的に実行させることが可能だったりしますが、個人的にはあまり使用しないです。
ALTER TABLE MOVE文は対象の表、もしくはパーティションを排他ロックしますので、
その途中で別セッションからレコードのUPDATE文が実行された場合には、
そのUPDATE文は「表セグメントの移動が完了するまで待機」させられます。
ここで疑問が生まれますよね?「UPDATE INDEXES」句も「表セグメントの移動後」に索引のRebuildを実行しますが、
待機中のUPDATE文と索引のRebuildはどちらが優先されるのでしょうか?
実は、待機中のUPDATE文が先に実行されます。これにより未コミットのレコードが存在する為、
索引Rebuildの処理がORAエラーで失敗することがあります。
なので、完全にDML文が実行されないと保証されていれば、UPDATE INDEXES句を付けても良いと思いますが、
私は専ら表のオンライン再定義を使用していますよ。

以上のように、津島博士は「基本、UPDATE INDEXES句を使うように」言われているのに対し、
しばちょう先生は、「個人的にはあまり使用しないです。」と言われています。

Oracle社としては、どちらが推奨なのでしょうか?

■津島博士からの回答

質問ありがとうございます。回答いたします。

まずは、UPDATE INDEXES句の使用についてですが、使用した方が良い場合も使用しない方が良い場合もあるかと思いますので、 どちらが推奨というより状況によって使い分けるのが良いかと思います。

それから、ご指摘の箇所は以下のような意味になりますが、ローカル索引についての注意が漏れていましたので、変更することにしました。

[変更前]
グローバル索引は、小さいサイズのパーティションではUPDATE GLOBAL INDEXESを使用した方が効果的ですが、
ローカル索引が存在してもメンテナンスされないので、どちらもメンテナンスする場合にはUPDATE INDEXESを使用してください。


以下のように変更しました。

(TRUNCATE PARTITIONではローカル索引がUNUSABLEになりませんので、サンプルのSQLもMOVE PARTITIONに変更しました)。


パーティションのデータが移動する操作(COALESCE、MERGE、SPLIT、MOVEなど)については、ローカル索引でもそのパーティションが UNUSABLEになります。そのため、Oracle Database 10gからローカル索引もメンテナンスされるように、以下のUPDATE INDEXES句(索引の自動更新)が追加されているので、どちらも更新したい場合はこれを使用してください。
ただし、ローカル索引については、内部的に 再構築が実行されるので、そのパーティションにDMLが実行されないときに行うようにしてください。

SQL> ALTER TABLE tab1 MOVE PARTITION p01 UPDATE INDEXES;

 

津島博士

 

ご質問 - 【第55回】オプティマイザ・ヒントについて

 

■ご質問

第55回 オプティマイザ・ヒントについて(https://blogs.oracle.com/otnjp/tsushima-hakushi-55)において、
>・システム生成
>システムで自動的に生成する識別子ですが、デフォルトの実行計画には出力されません(dbms_xplan.display_cursorなどのFORMATパラメータに’ALIAS’を指定することで、’Query Block Name’が出力されて確認できます)。

と書かれています。
このシステム生成された名前(SEL$2など)は、 一度決定すると、それ以降は変わらないものなのでしょうか。

dbms_xplan.display_cursorで確認した直後、ヒント句を指定して意図したどおりに動作したとしても、なんらかのタイミング(次回ハードパース時やSQLを少し変更したあと等)で名前が変わってしまい、ヒント句が無効になってしまわないかと、懸念しています。

以上、よろしくお願い致します。

 

■津島博士からの回答

質問ありがとうございます。回答いたします。

いつも読んでいただいてありがとうございます。

システムで生成する識別子は、SELECT文では主問合せと副問合せ(ビューも含む)に対しての識別子(SEL$1,SEL$2, …)ですので、SQLを変更するか問合せ変換されるかしないと変わることはありません。また、SQLの変更とは、副問合せを変更(追加、削除、順番の変更など)するような変更のことをいいます。

 

津島博士


ページトップへ戻る▲ 

 

津島博士のパフォーマンス講座 Indexページ ▶▶