0
1

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でHint使用方法

Last updated at Posted at 2024-07-16

はじめに

PostgreSQLはOracleとは異なり、SQL Hint機能を提供してないです。
そのため、Hint機能を使うために、Pg_hint_plan Extensionのインストールが必要です。
本記事では、Pg_hint_planのInstall方法とヒントの使用方法について説明します。

Pg_hint_planのInstall

#例:Postgresql15の場合
#File Downloadする
wget https://github.com/ossc-db/pg_hint_plan/archive/refs/tags/REL15_1_5_1.tar.gz

#圧縮を解凍
tar zvxf REL15_1_5_1.tar.gz
cd pg_hint_plan-REL15_1_5_1

#Install
make && make install

#pg_hint_plan Extension適用
#postgresql.confを修正します。
#parameter shared_preload_libraries項目にpg_hint_planを追加
...
shared_preload_libraries = 'pg_hint_plan'
...

#Postgresql再起動
#このコマンドは各自環境に違いますので、自分の環境に合わせて再起動を行います。
systemctl restart postgresql

#Extension作成
postgres=# CREATE EXTENSION pg_hint_plan ;
CREATE EXTENSION
postgres=# \dx
                    List of installed extensions
     Name     | Version |   Schema   |         Description
--------------+---------+------------+------------------------------
 pg_hint_plan | 1.5.1   | hint_plan  |
 plpgsql      | 1.0     | pg_catalog | PL/pgSQL procedural language

SQL Plan確認方法

#予想Plan確認
=# EXPLAIN
-# select /*+ HashJoin(a b)  */ *
-# from employees a join employees b
-# on a.id = b.id;
                                 QUERY PLAN
qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq
 Hash Join  (cost=156.71..268.36 rows=4565 width=108)
   Hash Cond: (a.id = b.id)
   ->  Seq Scan on employees a  (cost=0.00..99.65 rows=4565 width=54)
   ->  Hash  (cost=99.65..99.65 rows=4565 width=54)
         ->  Seq Scan on employees b  (cost=0.00..99.65 rows=4565 width=54)
(5 rows)

#実Plan確認
#analyze optionを使う場合、SQLが実行されますので注意してください。

=# EXPLAIN (analyze, buffers)
-# select /*+ HashJoin(a b)  */ *
-# from employees a join employees b
-# on a.id = b.id;
                                                       QUERY PLAN
qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq
 Hash Join  (cost=156.71..268.36 rows=4565 width=108) (actual time=1.846..3.462 rows=4607 loops=1)
   Hash Cond: (a.id = b.id)
   Buffers: shared hit=108
   ->  Seq Scan on employees a  (cost=0.00..99.65 rows=4565 width=54) (actual time=0.023..0.346 rows=4607 loops=1)
         Buffers: shared hit=54
   ->  Hash  (cost=99.65..99.65 rows=4565 width=54) (actual time=1.775..1.776 rows=4607 loops=1)
         Buckets: 8192  Batches: 1  Memory Usage: 476kB
         Buffers: shared hit=54
         ->  Seq Scan on employees b  (cost=0.00..99.65 rows=4565 width=54) (actual time=0.002..0.742 rows=4607 loops=1)
               Buffers: shared hit=54
 Planning Time: 0.176 ms
 Execution Time: 3.814 ms
(12 rows)

Hint使用

PostgresqlでHint適用はOracleと同じ形式になります。

postgres=# select /*+ Hint内容  */ * from employees a join employees b on a.id = b.id;
  • 今回テストに使うTable構成
\d employees
                                           Table "public.employees"
    Column     x         Type          x Collation x Nullable x                    Default
qqqqqqqqqqqqqqqnqqqqqqqqqqqqqqqqqqqqqqqnqqqqqqqqqqqnqqqqqqqqqqnqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq
 employee_id   x integer               x           x not null x nextval('employees_employee_id_seq'::regclass)
 first_name    x character varying(50) x           x          x
 last_name     x character varying(50) x           x          x
 department_id x integer               x           x          x
Indexes:
    "employees_pkey" PRIMARY KEY, btree (employee_id)
    "idx_employees_department_id" btree (department_id)
    "idx_employees_first_name" btree (first_name)
    "idx_employees_last_name" btree (last_name)


\d departments
                                             Table "public.departments"
     Column      x         Type          x Collation x Nullable x                      Default
qqqqqqqqqqqqqqqqqnqqqqqqqqqqqqqqqqqqqqqqqnqqqqqqqqqqqnqqqqqqqqqqnqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq
 department_id   x integer               x           x not null x nextval('departments_department_id_seq'::regclass)
 department_name x character varying(50) x           x          x
Indexes:
    "departments_pkey" PRIMARY KEY, btree (department_id)
    "idx_departments_department_id" btree (department_id)
  • Scan Method
    Index指定Hintを使用してidx_employees_department_idからemployees_pkeyに変更されています。
explain select * from employees where employee_id>100 and department_id=5;
                                         QUERY PLAN
qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq
 Bitmap Heap Scan on employees  (cost=5.25..54.75 rows=490 width=33)
   Recheck Cond: (department_id = 5)
   Filter: (employee_id > 100)
   ->  Bitmap Index Scan on ★idx_employees_department_id  (cost=0.00..5.13 rows=500 width=0)
         Index Cond: (department_id = 5)
(5 rows)

#Hint適用後
↓↓↓↓↓↓↓↓
explain select /*+ indexscan(employees employees_pkey) */ * from employees where employee_id>100 and department_id=5;
                                     QUERY PLAN
qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq
 Index Scan using ★employees_pkey on employees  (cost=0.28..157.98 rows=490 width=33)
   Index Cond: (employee_id > 100)
   Filter: (department_id = 5)
(3 rows)

  • Join Method
    Join Hintを利用して、Joinの種類を変更できます。
    Hint適用する前はHash JoinでJoinされてますが、Hintでnestloop & leading Hintを適用してNested Loop JoinとJoin順番が変更されていることが確認できます。
=# explain
-# SELECT
-# e.employee_id, e.first_name, e.last_name, d.department_name
-# FROM employees e
-# JOIN departments d ON e.department_id = d.department_id;
                                 QUERY PLAN
qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq
 ★Hash Join  (cost=1.23..111.91 rows=5000 width=147)
   Hash Cond: (e.department_id = d.department_id)
   ->  Seq Scan on ★employees e  (cost=0.00..92.00 rows=5000 width=33)
   ->  Hash  (cost=1.10..1.10 rows=10 width=122)
         ->  Seq Scan on ★departments d  (cost=0.00..1.10 rows=10 width=122)
(5 rows)

#Hint適用後
↓↓↓↓↓↓↓↓

=# explain
-# SELECT /*+ nestloop (e d) leading ((d e))*/
-# e.employee_id, e.first_name, e.last_name, d.department_name
-# FROM employees e
-# JOIN departments d ON e.department_id = d.department_id;
                                               QUERY PLAN
qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq
 ★Nested Loop  (cost=0.28..194.11 rows=5000 width=147)
   ->  Seq Scan on ★ departments d  (cost=0.00..1.10 rows=10 width=122)
   ->  Index Scan using idx_employees_department_id on ★ employees e  (cost=0.28..14.30 rows=500 width=33)
         Index Cond: (department_id = d.department_id)

他に使えるHintについては下記のサイトから確認ができます。
https://github.com/ossc-db/pg_hint_plan/blob/master/docs/hint_list.md

まとめ

今回はHint利用方法について紹介しました。
Postgresqlは基本的にHint機能を提供してないですが、Extensionを利用するとSQL tuningに
必須であるHint機能が使えるようになります。

0
1
0

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
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?