standingzzz's Oracle memo

OracleSQLチューニングの豊富な経歴を生かして、主に11gと12cのオプティマイザ動作の違いなどについて、実用的な検証結果をメモしています。

Oracle12c ヒント句による実行計画の制御[ORDERED, LEADING, USE_NL, INDEX, OPT_PARAM]

概要

SQLが望ましくない実行計画となっている場合に、
ヒント句により結合順などを制御する例をあげます。

Oracle Database 12c Enterprise Edition Release 12.2.0.1.0 - 64bit Production
CentOS Linux release 7.3.1611 (Core) 

検証

結合テスト用オブジェクト、データ用意

市場名と業種名はマスタ化して、メインテーブルには各コードを保持します。

実行計画の制御

stoke_nameが「東京」で始まる企業の、市場/業種を集計するSQLを例とします。


全部をメモリ上に読み込んで、HASH JOIN、MERGE JOINでガシャッという感じですね。
まあ、テーブル件数も少ないので、単体ではこの方が速いのは事実です。
しかし本番運用では多数のSQLが流れるので、こういった実行計画は
好ましくないことがほとんどです。という理屈をつけて、実行計画を制御します。


orderedヒント句は、SQLのテーブル記述順でどうですか、というだけなので、
結合順の選択肢が1つしかなく、その順序では実行計画が成り立たないと判断されると、
オプティマイザはヒント句を無視するので、効かないこともしばしば。
ここでは意図あってテーブルを結合順に並べているので、ヒント句は効きました。


今回の場合、orderedと同じ結合順をleadingに変えているだけなので、
意味合いは全く同じです。当然、実行計画も同じ。
orderedでもleadingでも、結合順はヒント句が効きましたが、
オプティマイザはやはりHASH JOINしたいようです。(間違いではありません)


しかし、本番システム上で1000多重で実行することを考えて、use_nlヒント句により、
結合方法をNestedLoopに変えて見ました。
まとめてメモリ上に読み込まずに、ループしながら必要な件数ずつ読み込むことで、
メモリリソースの使用を抑える意図です。
あとは、せっかく用意したstock_name用のインデックス、idx01_tab_stockを使って欲しいところ。
東京%の条件で、24件まで絞り込めるので。※この想定はオプティマイザには難しい部分

SQL> select count(*) from tab_stock where stock_name like '東京%';

  COUNT(*)
----------
        24

indexヒント句を入れると、これも何とも素直に効いてくれました。

access("S"."STOCK_NAME" LIKE '東京%')

今回のヒント句を入れたものが、必ずしも最適解というわけではありませんが、
オンラインで多数実行される場合に、メモリリソースを抑えるようなケースでは、
このような実行計画が無難なものとなりますね。


もう1つはおまけで。

opt_paramヒント句で、このSQL実行時のoptimizer_index_cost_adjの値を1(デフォルトは100)
に変更してみると、あらら。
leadingもuse_nlも無しで、この実行計画になりました。