| ■97216 / ) |
Re[1]: ACCESS FULL にならないSQLの書き方について |
□投稿者/ 魔界の仮面弁士 (3067回)-(2021/04/16(Fri) 09:44:46)
|
2021/04/16(Fri) 12:13:36 編集(投稿者)
■No97213 (ひろし さん) に返信 > ※質問用にSQLをシンプルにしていますが、実際にはもっと複雑なSQLとなります。 とはいえ今回は、提示されたシンプルな構造の場合の話に限定して良いのですよね。
データ量が多いテーブルから少量のデータのみを取り出すようなケースでは TABLE ACCESS FULL は非効率的ですが、総件数が多いテーブルの場合や 読みだすデータが大量の場合は、あえて TABLE ACCESS FULL に誘導した方が適切なケースもあります。
> 実行計画を見てみると、プライマリーキーで検索しているのにもかかわらず > TABLE ACCESS FULL > になってしまいます。 少なくとも、今回の SQL においては :id_From が NULL の時には全件走査以外の選択肢は無いわけで、 それが OR で繋がっている以上、事前の実行計画は TABLE ACCESS FULL にならざるを得ないかと。
手元に環境が無いので試せませんが、ひとまず OR を外して WHERE id > CAST(NVL(:id_From, RPAD(CHR(0), 10, CHR(0)) AS CHAR(10)) のような問い合わせにすれば、Oracle 11.2 環境では TABLE ACCESS BY INDEX ROWID になるものと予想します。12.1 以降であれば TABLE ACCESS BY INDEX ROWID BATCHED になるでしょう。
ただし、データ量が極端に多い場合の全件取得が目的の場合は要注意。 TABLE ACCESS FULL であればマルチブロックリードが行われますが、 TABLE ACCESS BY INDEX ROWID だとシングルブロックリードとなってしまうため、 キャッシュに載っていないブロックの物理 I/O が数倍に増えることがあるためです。
TABLE ACCESS BY INDEX ROWID BATCHED が使えるバージョンであれば、 パラレルリードされる見込みがあるものの、11.2 では非サポート…。
それが速度低下につながるかは、実環境で試さないと分からないですけれどね。 (大量のメモリを積んでキャッシュに載せている場合は、物理 I/O が無くなります)
> そこで、プログラム的には、IF文で分岐すると、SQLエディタのSQLをそのまま貼り付ける事が出来なくなってしまうため 一回の問い合わせ中に、WHERE の異なる 2 パターンの問い合わせを用意しても良いのであれば、 PL/SQL の REF CURSOR で受け渡しするようにすれば、PL/SQL の IF で分岐できるかと思います。
|
|