C# と VB.NET の質問掲示板

わんくま同盟

ASP.NET、C++/CLI、Java 何でもどうぞ

C# と VB.NET の入門サイト


(過去ログ 168 を表示中)
■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 で分岐できるかと思います。
返信 編集キー/


管理者用

- Child Tree -