Database Support Blog

  • Oracle Database
2020.12.17

Oracle Databaseバージョンアップ後の性能劣化で試したい暫定対処

Oracle Database

この記事は、JPOUG Advent Calendar 2020 の17日目の記事です。

16日目はmoritaxp_oironさんの記事『DatabaseのAT(オートマ)、Autonomous Database を見る 』でした。Autonomous Data Warehouse(ADW)でできること、できないこと(やらなくても良いこと)をわかりやすく解説してくださっていて非常に勉強になりました。

ちなみに私の普通自動車免許はMTですが、最後にMT車に乗ったのは教習所です。

バージョンアップ後によくいただくご相談

長期サポートリリースの19cが昨年リリースされたことで、19cをご利用されているお客様からのお問い合わせも徐々に増えてきました。新しいバージョンがリリースされると必ずいただくのが「移行後に特定のクエリが遅延するようになった」というお問い合わせです。

バージョンが上がることで様々な機能や仕様が追加・改善されるため、多くのケースではクエリのパフォーマンスは改善、もしくは据え置きです。しかし、中にはまれにオプティマイザの動作や機能・仕様の変更によりクエリの性能が落ちてしまうこともあります。

また、バージョンアップに伴い、移行先バージョンを使用した開発環境(テストデータ)では問題なかったクエリが、本番環境で遅延するといったお問い合わせもいただきます。

多くのケースでは実行計画の差異や適切な実行計画が選択されていないことに起因するため、SQLトレース(EVENT 10046)やCBOトレース(EVENT 10053)をご提供いただき、実行計画に差がないか?などの調査をサポートセンターで行いますが、お客様から「サポートの回答を待っている間に何か簡単に試せることはないか?」というご要望をいただくことがあります。

今回は、バージョンアップ後に発生した or 開発環境では発生しなかったクエリの性能劣化が起きたときにユーザ側で試せることをまとめます。

※注意※
あくまで「問題発生箇所の切り分けや暫定策として簡単に試せること」であり、解決を保証するものではない点、そのままの運用を推奨していることではない点、ご了承ください。


①OPTIMIZER_FEATURES_ENABLEの変更

バージョンアップ後のクエリ性能劣化の切り分けや暫定対処策として、効果がある可能性が高い方法がOPTIMIZER_FEATURES_ENABLEの変更です。

このパラメータはコストベース・オプティマイザ(CBO)の動作を指定したバージョンに制限します。移行前のバージョンで期待したパフォーマンス実績がある場合には有効な方法です。

指定方法としては、パラメータ、ヒント句があります。パラメータはインスタンス全体にも指定可能ですが動作確認としてはまずはセッション単位で指定します。

 
 -- ALTER SESSION で11.2.0.4 に設定
 SQL> ALTER SESSION SET OPTIMIZER_FEATURES_ENABLE='11.2.0.4';
 
 -- ヒント句で11.2.0.4 に設定
 SQL> SELECT /*+ OPTIMIZER_FEATURES_ENABLE('11.2.0.4') */ empno,ename, …;
 

移行前のバージョンを指定することで改善した場合は、バージョンアップの過程で追加された機能や仕様、もしくは実行計画生成のアルゴリズムに起因して異なる実行計画が生成された可能性が高いと言えます。


②動的統計の調整

動的統計はSQLのパース時に動作し、クエリ実行時点のデータを元に動的に統計情報を取得します。動的統計が動作するかは、初期化パラメータOPTIMIZER_DYNAMIC_SAMPLINGに指定されているレベルと、クエリ実行対象の表の統計情報取得状況に依存します。

レベルごとの動作の違いは、SQLチューニング・ガイド「動的統計レベルについて 」をご参照ください。

移行する前と後、開発環境と本番環境ではクエリの対象となる表に対し、統計情報の取得状況に差がある場合があります。このようなケースではクエリ実行時の動的統計の動作に違いが出てしまい、実行計画が異なることでパフォーマンスに影響が出ることもあります。

レベル0(動的統計を使用しない)、レベル11(CBOが必要と判断した場合に動作)の両方で試すことでクエリの性能改善がみられるかご確認ください。

 
 -- 0に設定する例
 SQL> ALTER SESSION SET OPTIMIZER_DYNAMIC_SAMPLING = 0;
 
 -- 11に設定する例
 SQL> ALTER SESSION SET OPTIMIZER_DYNAMIC_SAMPLING = 11;
 

③バインドピーク機能の無効化

バインドピークでは、バインド変数の入力値を考慮した実行計画を生成します。バインドピークをはじめとしたオプティマイザの動作改善機能はバージョンが上がるごとに追加されていますので、基本的にはこれらの機能を使用をすることで最適な実行計画が選択されます。

あくまで切り分けの観点で、もしバインド変数を利用しているSQLでの遅延が起きている場合には、該当機能をOFFにすることで性能改善がみられるかご確認ください。

 
 -- バインドピークをOFFに変更
 SQL> ALTER SESSION SET “_optim_peek_user_binds” = FALSE;
 

④ヒストグラムの調整

ヒストグラムは列に含まれるデータ分布の情報で、統計情報取得時に、デフォルトでは全列に対して取得されます。データに偏りがある場合にはこちらの情報を取得することでより適切な実行計画が生成されます。

ヒストグラムは文字データの場合、前半32byteで偏りを判断します。そのため、住所データなどの「○○○県△△△市××××町一丁目一番一号」と「○○○県△△△市××××町一丁目一番二号」は同じデータとして認識されます。

もし、このようなデータが条件に入るクエリを実行していて、本番環境と開発環境でテストデータに差がある場合には、ヒストグラムの違いで異なる実行計画となり、パフォーマンスに影響を与える可能性があります。ヒストグラム統計の取得や削除により性能改善が見られるかご確認ください。

 
 -- ヒストグラムを取得しない統計情報の取得
 SQL> EXEC DBMS_STATS.GATHER_TABLE_STATS -
 > ('スキーマ名','表名', NO_INVALIDATE=>FALSE, -
 > METHOD_OPT => 'FOR ALL COLUMNS SIZE 1');
 
 -- 取得済みの統計情報からヒストグラムを削除
 SQL> EXEC DBMS_STATS.DELETE_COLUMN_STATS -
 > ('スキーマ名','表名','列名',NO_INVALIDATE=>FALSE, -
 > COL_STAT_TYPE => 'HISTOGRAM');
 

※ヒストグラムの取得は通常通りDBMS_STATS.GATHER_TABLE_STATSの実行です


⑤拡張統計の取得

拡張統計は列グループや関数に基づいた統計情報です。クエリ内に同じ表に対する and / or の条件が含まれる場合は、拡張統計を取得することでカーディナリティ(戻される行数)の予測を改善できます。

SQL実行計画を改善する拡張統計(列グループ統計)の取得方法
https://www.ashisuto.co.jp/db_blog/article/20160714_extended_stats.html

同一テーブルに対する and / or の条件を使用しており、本番環境と開発環境で利用しているデータが異なる状況でパフォーマンスに差が出ているケースでは、拡張統計の取得有無が実行計画の生成に影響を与えている可能性があります。拡張統計の取得で性能改善が見られるかご確認ください。

上述のブログでは、DBMS_STATS.CREATE_EXTENDED_STATSを使用して明示的に列グループを作成していますが、ワークロードに基づき、作成する方法もあります。

 
 -- ワークロード監視を有効化(10分)
 SQL> CONN / AS SYSDBA
 SQL> EXEC DBMS_STATS.SEED_COL_USAGE (null,null,600);
  
 -- 指定した期間内に対象のSQLを実行(EXPLAIN PLAN FORで実際に実行しなくても可)
 SQL> CONN USER/PASSWORD
 SQL> EXPLAIN PLAN FOR SELECT * FROM tab WHERE col1=’A’ AND col2=’B’;
 
 -- 記録された列使用情報を確認
 SQL> set long 10000
 SQL> SELECT DBMS_STATS.REPORT_COL_USAGE('USER','TAB') FROM DUAL;
 
 -- 表名を指定して列グループを作成
 SQL> SELECT DBMS_STATS.CREATE_EXTENDED_STATS('USER','TAB') FROM DUAL;
 
 -- 出力例
 --------------------------------------------------------------------------------
 ###############################################################################
 
 EXTENSIONS FOR USER.TAB
 ........................
 
 1. (COL1, COL2) : SYS_STUNA$6DVXJXTP05EH56DTIR0X created
 ###############################################################################
 
 -- 統計情報を取得
 SQL> EXEC DBMS_STATS.GATHER_TABLE_STATS ('USER','TAB', NO_INVALIDATE=>FALSE);
 

拡張統計は実際にクエリが利用するWHERE句の条件に合わせて取得する必要があります。たとえば、col1、col2、col3で取得した列グループ統計は、col1、col2の条件を指定したクエリでは使用されないため、注意が必要です。


⑥アウトラインヒントの使用

移行前や開発環境など、クエリの性能劣化が起きていない(期待した時間内に結果が返る)環境がある場合に有効な方法です。特定の実行計画にするためのヒント句のリストを取得します。

CBOトレースを取得するため、対象のSQLをハードパースさせる必要があります。

 
 -- 対象のADDRESS、HASH_VALUEを確認する
 SQL> conn /as sysdba
 SQL> SELECT SQL_ID,ADDRESS,HASH_VALUE,SQL_FULLTEXT FROM V$SQL
 2 WHERE SQL_FULLTEXT LIKE '%select col1 from test%';
 
 SQL_ID        ADDRESS          HASH_VALUE SQL_FULLTEXT
 ------------- ---------------- ---------- ---------------------
 5qmzjwsrrjjw3 00007FFC2A1BA1D0 796444547  select col1 from test
 
 -- ハードパースをさせるため、対象のクエリを共有プールからパージ
 SQL> EXEC DBMS_SHARED_POOL.PURGE ('00007FFC2A1BA1D0,796444547','C');
 
 --CBOトレースのイベントを有効にする
 SQL> CONN USER/PASSWORD
 SQL> ALTER SESSION SET EVENTS '10053 LEVEL 1';
 
 -- 対象のクエリを実行(ハードパース)し、トレースを解除
 SQL> select col1 from test;
 SQL> ALTER SYSTEM SET EVENTS '10053 OFF’;
 
 -- トレースの出力先を確認
 SQL> SELECT VALUE FROM V$DIAG_INFO WHERE NAME = ‘Default Trace File’;
 

出力されたトレースファイル内を「Outline Data」で検索し「/*+ ~ */」内の内容を移行先(遅い)環境のクエリにヒント句として埋め込むことで性能が改善されるかご確認ください。

 
 SELECT
 /*+
 BEGIN_OUTLINE_DATA
  IGNORE_OPTIM_EMBEDDED_HINTS
  OPTIMIZER_FEATURES_ENABLE('19.1.0')
  DB_VERSION('19.1.0')
  ALL_ROWS
  OUTLINE_LEAF(@"SEL$1")
  FULL(@"SEL$1" "TEST"@"SEL$1")
 END_OUTLINE_DATA
 */ col1 from test;
 

最後に

バージョンアップ前や開発環境からの移行後に発生するクエリ性能劣化については、実際のサポートでは「新機能/仕様変更によって実行計画が変わった」もしくは「本番環境と開発環境で同一の実行計画だが、使用しているデータが異なるため最適な実行計画は異なる」ことが原因のケースが多く確認できます。

今回ご紹介した方法は、サポートからの回答を待つ間に、実データや他ユーザに極力影響を与えずに簡単に試せる方法を記載しました。そのため、パラメータの変更などは「ALTER SESSION」で行い、SQL*Plusでクエリを実行することを前提としています。

実際にはアプリケーションからの実行で、ALTER SESSIONの埋め込みが難しいケースもあると思います。そのようなケースでは次の例のようにLOGONトリガーを使用することで、アプリケーションからの接続のタイミングで処理実行ユーザに対してALTER SESSIONを有効にすることができます。

 
 -- LOGONトリガーでALTER SESSIONを有効にする
 SQL> CONN USER/PASSWORD
 SQL> CREATE OR REPLACE TRIGGER tr1 AFTER LOGON ON SCHEMA
 2 BEGIN
 3 EXECUTE IMMEDIATE
 4 'ALTER SESSION SET OPTIMIZER_FEATURES_ENABLE=''11.2.0.4'' ';
 5 END;
 6 /
 

確認が終わったら必ずトリガーの削除を忘れないようにしましょう!

 
 SQL> DROP TRIGGER tr1;
 

明日のJPOUG Advent Calendar 2020 の担当はryota_hnkさんです。ryota_hnkさん、よろしくお願いします!


筆者情報

大野 高志

ビジネスインフラ技術本部

2007年アシスト入社。Oracle Databaseのサポート業務を経て、サポートセンターに蓄積されたナレッジを使用したサービスの立ち上げに従事。現在は「 アシストの超サポ 」を広め、カスタマーエンゲージメントの構築を実現するための活動を行っている。


■商標に関して
OracleとJavaは、Oracle Corporation 及びその子会社、関連会社の米国及びその他の国における登録商標です。
文中の社名、商品名等は各社の商標または登録商標である場合があります。

関連している記事

  • Oracle Database
2020.10.30

Standard Edition High Availabilityの実力を探る

Oracle Database 19cからSERACが提供されなくなり、その代替ソリューションとしてSEHAが発表されました。代替機能として提供されたStandard Edition High Availability(SEHA)をSEHAを徹底検証しました。

  • Oracle Database
  • Oracle Cloud
  • EDB Postgres
2020.09.17

DB関連セッション視聴ガイド 【アシストテクニカルフォーラム2020】

2020年10月22日(木)に開催されるオンライン技術フォーラム、アシストテクニカルフォーラム2020の全36セッションの中から、データベースに関連するセッションをご案内します。

  • Oracle Database
2020.08.05

DB事例多数!アシストオンラインフォーラム2020 目的別視聴ガイド

アシストオンラインフォーラム2020では140を超えるセッションをご視聴いただけます。数多くのセッションの中から、データベースに関連したセッションの視聴ガイドを情報収集の目的別に紹介します。

ページの先頭へ戻る