はじめに
複数のテーブルを何度も結合するような処理を実行する場合、処理の途中のデータセットが大きいと、大きなデータセットのまま後続の処理も実行するため、SQL実行時間が比較的長くなるケースがあります。
このような状況を避けるためには、処理の初期段階で出来る限りデータセットを小さくする(WHERE句で抽出データを絞る)ことが大切です。
しかしながら、SQLの記述内容によっては、WHERE句で条件を指定しても初期段階でデータセットが絞り込まれないケースがあります。
本記事では、上記のケースに該当するSQL記述内容を紹介します。
データセットが絞り込まれているか確認するためには、実行計画の「Rows」を確認します。
読み込みデータ量が小さい例
/*** Rowsが4M(約400万行の読み込み)の実行例 ***/
dbadmin=> EXPLAIN
dbadmin-> SELECT count(*) FROM lineorder WHERE lo_orderdate = 19920101;
QUERY PLAN
---------------------------------------------------------------------------
------------------------------
QUERY PLAN DESCRIPTION:
------------------------------
EXPLAIN
SELECT count(*) FROM lineorder WHERE lo_orderdate = 19920101;
Access Path:
+-GROUPBY NOTHING [Cost: 2M, Rows: 1] (PATH ID: 1)
| Aggregates: count(*)
| +---> STORAGE ACCESS for lineorder [Cost: 2M, Rows: 4M] (PATH ID: 2) /* Rowsが4M */
| | Projection: public.LINEORDER_DBD_2_rep_d1223
| | Filter: (lineorder.LO_ORDERDATE = 19920101)
<以降、省略>読み込みデータ量が増加する例(上記の例よりも大きい)
/*** Rowsが750M(約7億5000万行の読み込み)の実行例 ***/
dbadmin=> EXPLAIN
dbadmin-> SELECT count(*) FROM lineorder WHERE lo_orderdate != 19920101;
QUERY PLAN
---------------------------------------------------------------------------
------------------------------
QUERY PLAN DESCRIPTION:
------------------------------
EXPLAIN
SELECT count(*) FROM lineorder WHERE lo_orderdate != 19920101;
Access Path:
+-GROUPBY NOTHING [Cost: 2M, Rows: 1] (PATH ID: 1)
| Aggregates: count(*)
| +---> STORAGE ACCESS for lineorder [Cost: 2M, Rows: 750M] (PATH ID: 2) /* Rowsが750M(約7億5000万行の読み込み) */
| | Projection: public.LINEORDER_DBD_2_rep_d1223
| | Filter: (lineorder.LO_ORDERDATE <> 19920101)
<以降、省略>SQL記述の留意事項
否定演算子を使用する場合
否定演算子を使用している場合は、読み込みデータ量が増加します。
読み込みデータ量 “小”
dbadmin=> SELECT count(*) FROM lineorder WHERE lo_orderdate = 19920101;読み込みデータ量 “増”
dbadmin=> SELECT count(*) FROM lineorder WHERE lo_orderdate != 19920101;WHERE句で指定する条件の左辺に関数を使用する場合
WHERE句で指定する条件の左辺に関数を使用する場合は、読み込みデータ量が増加します。
読み込みデータ量 “小”
dbadmin=> SELECT count(*) FROM lineorder WHERE lo_orderdate = 19920101;読み込みデータ量 “増”
dbadmin=> SELECT count(*) FROM lineorder WHERE TO_CHAR(lo_orderdate) = '19920101';LIKE演算子を使用して中間一致または後方一致で検索する場合
LIKE演算子を使用して中間一致または後方一致で検索する場合は、読み込みデータ量が増加します。
読み込みデータ量 “小”
dbadmin=> SELECT count(*) FROM lineorder WHERE lo_orderpriority LIKE '1-URGEN%';読み込みデータ量 “増”
dbadmin=> SELECT count(*) FROM lineorder WHERE lo_orderpriority LIKE '%-URGENT';
dbadmin=> SELECT count(*) FROM lineorder WHERE lo_orderpriority LIKE '%-URGEN%';IS NULL演算子を使用する場合
IS NULL演算子を使用する場合は、読み込みデータ量が増加します。
読み込みデータ量 “増”
dbadmin=> SELECT count(*) FROM lineorder WHERE lo_orderdate IS NULL;ビューを作成し、ビューに対して条件を指定する場合(1)
ビュー内のSELECTリストに検索条件項目への関数を含む場合、読み込みデータ量が増加します。
本例で使用するオブジェクト
種類 | オブジェクト名 |
|---|---|
トランザクションテーブル | 「lineorder」 |
マスタテーブル | 「date1」 |
ビュー1 | 「lo_view」 |
ビュー2 | 「lo_view2」 |
ビューの内容
dbadmin=> /***** ビュー1の内容 *****/
dbadmin=> CREATE OR REPLACE VIEW lo_view as
dbadmin-> SELECT
dbadmin-> l.lo_orderdate,
dbadmin-> l.lo_orderpriority,
dbadmin-> d.d_datekey,
dbadmin-> d.d_date
dbadmin-> FROM lineorder AS l
dbadmin-> LEFT OUTER JOIN date1 AS d ON l.lo_orderdate = d.d_datekey;
CREATE VIEW
dbadmin=> /***** ビュー2の内容 *****/
dbadmin=> CREATE OR REPLACE VIEW lo_view2 as
dbadmin-> SELECT
dbadmin-> l.lo_orderdate,
dbadmin-> SUBSTR(l.lo_orderpriority, 1, 8) AS lo_orderpriority, /*** ビュー1と比較して関数を使用 ***/
dbadmin-> d.d_datekey,
dbadmin-> d.d_date
dbadmin-> FROM lineorder AS l
dbadmin-> LEFT OUTER JOIN date1 AS d ON l.lo_orderdate = d.d_datekey;
CREATE VIEW読み込みデータ量 “小”
dbadmin=> SELECT count(*) FROM lo_view WHERE lo_orderpriority='1-URGENT';読み込みデータ量 “増”
dbadmin=> SELECT count(*) FROM lo_view2 WHERE lo_orderpriority='1-URGENT';ビューを作成し、ビューに対して条件を指定する場合(2)
外部結合を行うビューを作成し、そのビューに対して条件を指定する場合、以下の動作をとります。
・トランザクションテーブル(結合元)の項目を条件に指定した場合 … 読み込みデータ量が小さい
・マスタテーブル(結合先)の項目を条件に使用した場合 … 読み込みデータ量が増加
詳細は以下の記事をご参照ください。
<外部結合を行っているViewに条件を付けて検索する際の注意点>
https://www.ashisuto.co.jp/cm/analytics-database/outer_view.html
参考
<SQLの実行計画を確認する方法>
https://www.ashisuto.co.jp/cm/analytics-database/sql-plan.html
検証バージョンについて
この記事の内容はVertica 9.2で確認しています。
更新履歴
2020/02/28 誤植を修正(「IS NULL演算子を使用する場合」の箇所)
2019/12/26 本記事を公開