76
40

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

PostgreSQLで同じ結果が得られるクエリの実行計画を確認してみる

Posted at

はじめに

本記事では同じ結果が得られるUNIONとCASE式を使用して実行計画を確認し、どちらの方がパフォーマンスが良いのか確認していきたいと思います!
実行計画の確認方法がわからない方は「PostgreSQLで実行計画を確認してみる」を参考にしてください🙌

準備

まずクエリを叩く為のテーブルを準備します☝️

-- テーブル作成
CREATE TABLE Items
(   item_id     INTEGER  NOT NULL, 
       year     INTEGER  NOT NULL, 
  item_name     CHAR(32) NOT NULL, 
  price_tax_ex  INTEGER  NOT NULL, 
  price_tax_in  INTEGER  NOT NULL, 
  PRIMARY KEY (item_id, year));

-- データ追加
INSERT INTO Items VALUES(100,  2000,   'カップ'        ,500,   525);
INSERT INTO Items VALUES(100,   2001,   'カップ'        ,520,   546);
INSERT INTO Items VALUES(100,   2002,   'カップ'        ,600,   630);
INSERT INTO Items VALUES(100,   2003,   'カップ'        ,600,   630);
INSERT INTO Items VALUES(101,   2000,   'スプーン'      ,500,   525);
INSERT INTO Items VALUES(101,   2001,   'スプーン'      ,500,   525);
INSERT INTO Items VALUES(101,   2002,   'スプーン'      ,500,   525);
INSERT INTO Items VALUES(101,   2003,   'スプーン'      ,500,   525);
INSERT INTO Items VALUES(102,   2000,   'ナイフ'        ,600,   630);
INSERT INTO Items VALUES(102,   2001,   'ナイフ'        ,550,   577);
INSERT INTO Items VALUES(102,   2002,   'ナイフ'        ,550,   577);
INSERT INTO Items VALUES(102,   2003,   'ナイフ'        ,400,   420);

UNION と CASE を使用して同じ結果を取得する

UNION

SELECT item_name, year, price_tax_ex AS price
FROM Items
WHERE year <= 2001
UNION
SELECT item_name, year, price_tax_in AS price
FROM Items
WHERE year >= 2002
ORDER BY item_name, year;

CASE

SELECT item_name, year,
CASE WHEN year <= 2001 THEN price_tax_ex
     WHEN year >= 2002 THEN price_tax_in END AS price
FROM Items;

実行結果(UNION / CASE)

以下のようにUNION / CASEどちらも同じ結果を返します👍

              item_name               | year | price 
--------------------------------------+------+-------
 カップ                               | 2000 |   500
 カップ                               | 2001 |   520
 カップ                               | 2002 |   630
 カップ                               | 2003 |   630
 スプーン                             | 2000 |   500
 スプーン                             | 2001 |   500
 スプーン                             | 2002 |   525
 スプーン                             | 2003 |   525
 ナイフ                               | 2000 |   600
 ナイフ                               | 2001 |   550
 ナイフ                               | 2002 |   577
 ナイフ                               | 2003 |   420
(12 rows)

実行計画を確認する

UNION

                                                          QUERY PLAN                                                          
------------------------------------------------------------------------------------------------------------------------------
 Sort  (cost=51.02..51.78 rows=306 width=140) (actual time=0.775..0.778 rows=12 loops=1)
   Sort Key: items.item_name, items.year
   Sort Method: quicksort  Memory: 25kB
   ->  HashAggregate  (cost=35.33..38.39 rows=306 width=140) (actual time=0.489..0.497 rows=12 loops=1)
         Group Key: items.item_name, items.year, items.price_tax_ex
         Batches: 1  Memory Usage: 37kB
         ->  Append  (cost=0.00..33.03 rows=306 width=140) (actual time=0.377..0.396 rows=12 loops=1)
               ->  Seq Scan on items  (cost=0.00..15.75 rows=153 width=140) (actual time=0.376..0.380 rows=6 loops=1)
                     Filter: (year <= 2001)
                     Rows Removed by Filter: 6
               ->  Seq Scan on items items_1  (cost=0.00..15.75 rows=153 width=140) (actual time=0.009..0.011 rows=6 loops=1)
                     Filter: (year >= 2002)
                     Rows Removed by Filter: 6
 Planning Time: 3.541 ms
 Execution Time: 1.305 ms
(15 rows)

CASE

                                             QUERY PLAN                                              
-----------------------------------------------------------------------------------------------------
 Seq Scan on items  (cost=0.00..16.90 rows=460 width=140) (actual time=0.132..0.136 rows=12 loops=1)
 Planning Time: 0.505 ms
 Execution Time: 0.302 ms
(3 rows)

パフォーマンス差のポイント😳

Execution Time(処理時間)
UNION:1.305 ms
CASE:0.302 ms

Seq Scan(テーブル全体をスキャン)
UNION:(2回スキャン)
 Seq Scan on items
 Seq Scan on items items_1
CASE:(1回スキャン)
 Seq Scan on items

CASE式はUNIONよりパフォーマンスが良くなりやすい

SQLで同じ結果を取得できる場合でも、UNION と CASE 式で処理性能に差が出ることがあります。

CASE式の特徴

  • 1つのテーブルを1回スキャンすればよい
  • 条件が単純な場合では特に高速

UNIONの特徴

  • 複数のSELECTを結合するため、テーブルを複数回スキャンすることが多い
  • 条件が単純な場合は、CASE式に比べて処理時間が長くなりやすい

UNIONを使用したほうがパフォーマンスが良いケースもある

SQLで複数の条件を組み合わせてデータを取得する場合、CASE式を使った方が高速な場合が多いですが、UNIONを使った方がパフォーマンスが良くなるケースも存在します。

例えば以下のような状況等です。

  • インデックスを利用できる場合
  • 複雑な条件でテーブルを分割したほうが効率的な場合
    ※実際のパフォーマンスはテーブルサイズや条件によって変化します。実行計画を確認して最適な方法を選ぶのがベストです。🧐

まとめ

  • CASE式は単純条件で高速
  • UNIONは条件やインデックス次第ではパフォーマンスが高くなることもある
  • 実行計画を確認して、パフォーマンスをチェックするのがベスト

私自身まだまだ勉強中ですが、引き続き実践しながら学んだことを発信していきたいと思います!🐊

76
40
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
76
40

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?