ユーザ用ツール

サイト用ツール


serverapps:db:postgresql

文書の過去の版を表示しています。


PostgreSQL

zfsと組み合わせる

4Core メモリ16GB のVM想定

インストール

# pkg install postgresqlXX-server

ZFSレイヤーの設定

Disk追加はここらへん(パーティション追加して zfs を作成)を参照

# 1. PostgreSQL用のデータセット(親)作成(マウントはまだしない)
zfs create -p -o canmount=off zdata/var/db/postgres

# 2. バージョンごとのデータセットを作成(将来のアップグレードが楽になりそう)
# 例: PostgreSQL 18の場合
zfs create -o mountpoint=/var/db/postgres/data18 \
           -o recordsize=8k                      \
           -o primarycache=metadata              \
           zdata/var/db/postgres/data18

# 3. 所有者の変更
chown -R postgres:postgres /var/db/postgres/data18
chmod 700 /var/db/postgres/data18

OSレイヤーの設定 (/boot/loader.conf)

ZFSがメモリを食いつぶさないよう、ARC(キャッシュ)を制限1)

# cat /boot/loader.conf
# ZFS ARCの上限を8GBに設定(残り8GBをOSとPGで分け合う)
vfs.zfs.arc.max="8G"

再起動

# shutdown -r now

確認

# パラメータ名で確認
sysctl vfs.zfs.arc.max

# 実際に適用されている最大値を確認(前述と同じ)
sysctl kstat.zfs.misc.arcstats.c_max

PostgreSQL起動設定 (/usr/local/etc/rc.conf.d/postgresql)

# 1. ディレクトリ作成
mkdir -p /usr/local/etc/rc.conf.d
touch /usr/local/etc/rc.conf.d/postgresql

# 2. 設定の書き込み
sysrc -f /usr/local/etc/rc.conf.d/postgresql postgresql_enable="YES"
sysrc -f /usr/local/etc/rc.conf.d/postgresql postgresql_data="/var/db/postgres/data18"

## ログ出力先の指定 (postgresql_logdir)
## これは好みで
mkdir /var/log/postgresql
chown postgres /var/log/postgresql
sysrc -f /usr/local/etc/rc.conf.d/postgresql postgresql_logdir="/var/log/postgresql"


# 3. 初期化フラグ
sysrc -f /usr/local/etc/rc.conf.d/postgresql postgresql_initdb_flags="\
  --data-checksums \
  --encoding=UTF-8 \
  --no-locale \
  --auth-local=peer \
  --auth-host=scram-sha-256 \
  --set password_encryption=scram-sha-256 \
  --set shared_buffers=4GB \
  --set work_mem=64MB \
  --set maintenance_work_mem=512MB \
  --set max_connections=200 \
  --set autovacuum_max_workers=4"

PostgreSQL initdb オプション設定一覧

オプション 役割・意味 設定の狙い・メリット
—-data-checksums データチェックサムの有効化 ディスク上の物理的なデータ破損を検知可能にする(必須級の安全策)
—-encoding=UTF-8 文字エンコーディングの設定 データベース全体の文字コードをUTF-8に固定する
—-no-locale ロケール(言語・文化設定)の無効化 OS依存のソート順などを排除し、パフォーマンス向上とOS更新時の不整合を防止する
—-auth-local=peer ローカル接続の認証方式 OSユーザーとDBユーザーが一致すればパスワードなしで接続を許可する(安全かつ便利)
—-auth-host=scram-sha-256 ネットワーク接続の認証方式 パスワード認証に最も安全なSCRAM-SHA-256方式を強制する
—-set password_encryption=scram-sha-256 パスワード保存形式の暗号化 ユーザー作成時に保存されるパスワードハッシュをSCRAM形式に固定する
—-set shared_buffers=4GB 共有バッファ(メモリキャッシュ) メモリ上にデータを保持する領域。16GBメモリに対し4GBを割り当て高速化を図る
—-set work_mem=64MB 作業用メモリ(クエリごと) 複雑なソートや集計で各プロセスが使用するメモリ。多すぎるとOOMの原因になるため64MBに調整
—-set maintenance_work_mem=512MB メンテナンス用メモリ INDEX作成やVACUUM時に使用する。大きくすることで管理タスクが高速化する
—-set max_connections=200 最大同時接続数 同時にDBへ接続できる最大数。複数サービス同居を考慮しデフォルトより多めに設定
—-set autovacuum_max_workers=4 Autovacuumワーカー数 不要領域の掃除を並列で行う数。複数DBのメンテナンスを滞らせないよう4に増加

エンコーディング関連

  • encoding=UTF-8
  • no-locale

以下の観点でこう変更した

  • OSアップデートによる「インデックス破損」
    • FreeBSDやLinuxのマイナーアップデートで、OS側のロケール定義(glibcやlibcのソート順)がわずかに変更されることがあります。このとき、DB側のインデックスとOS側のルールに不整合が起き、「検索にヒットしないデータが出る」「重複エラーで書き込めない」といった、復旧が困難な破損を招くリスクがあります。
    • PostgreSQL 17.1 のリリースノートでは、LC_CTYPE が C で LC_COLLATE が他のロケールという稀な構成で、問い合わせ結果が誤り、文字列インデックスが破損する可能性があったため、影響を受けるインデックスの再作成が必要と明記されています。
    • SRA OSS の技術情報でも同じ趣旨が説明されており、その組み合わせでは文字列インデックスが破損しうるとされています
  • パフォーマンスの劣化:
    • ja_JP ロケールは文字列比較のたびに複雑な言語ルールを計算するため、C ロケールに比べてソート性能が数倍〜十数倍遅くなることがあります。

代替案

  • 読み仮名カラムを持つ
    • name_kana カラムを作り、そこに平仮名を入れて、そのカラムでソート
    • C ロケールでも、平仮名やカタカナの数値順は五十音順とほぼ一致するため、実用上の問題はないはず
  • クエリ時にロケールを指定する (ICU規格)
    • PostgreSQL 15以降では、DB全体を C ロケールにしても、特定のクエリや特定のカラムにだけ、不変のロケール定義(ICUプロバイダ)を適用可能
-- 必要なときだけ日本語ソートを適用(※事前にICUサポートが必要)
SELECT name FROM users ORDER BY name COLLATE "ja-JP-x-icu";

これなら、基本は高速、必要な時だけ日本語順という「いいとこ取り」が可能2)

運用指針は以下の通りとした

項目 方針 理由
OS更新時の運用 特になし (メンテナンスフリー) C ロケール採用によりOS依存を排除したため
インデックス管理 定期的な ANALYZE のみ 破損リスクがないため REINDEX 運用は不要
ソート順の担保 アプリケーション/設計で解決 DBの整合性を最優先とするため

データベースの初期化と起動

# 初期化(ここで--data-checksums等が適用される)
service postgresql initdb

以下の様に設定と違う値が表示されるが、これはDefaultを表示しているだけの模様

selecting default "max_connections" ... 100
selecting default "shared_buffers" ... 128MB

var/db/postgres/data18/postgresql.conf の中身をチェックすると反映されている

# 起動
service postgresql start
# 設定値の確認(SQLで直接聞く)
su - postgres -c "psql -c 'SHOW shared_buffers; SHOW max_connections; SHOW data_checksums;'"
 shared_buffers
----------------
 4GB
(1 row)

 max_connections
-----------------
 200
(1 row)

 data_checksums
----------------
 on
(1 row)

クライアント認証

/var/db/postgres/data/pg_hba.conf に設定します。
標準では自分自身からの接続のみを許可しています。

# TYPE  DATABASE        USER            CIDR-ADDRESS            METHOD
# 1. ローカル(OS上のソート接続)は postgres ユーザーも含め Peer認証で許可
local   all             all                                     peer

# 2. 【重要】ネットワーク経由の postgres ユーザー(管理者)は一律拒否
host    all             postgres        0.0.0.0/0               reject
host    all             postgres        ::/0                    reject  
# 3. ネットワーク経由の一般ユーザーは、特定のLAN内からのみ SCRAM認証で許可
host    all             all             192.168.0.0/24          scram-sha-256

これで、管理者 postgres だけはネットワーク経由を拒否し、192.168.0.xxxからの接続が許可されます。3)

ほかからアクセスする場合には、postgresql.confのlisten_addresses も変更が必要です。

listen_addresses = '*'

管理者 password変更

root(postgres)ユーザのパスワードを変更します。4)

alter role postgres with password 'xxxxxxxxxxxxxxxxxxxx';

普通の場合

5)

インストール

# pkg install postgresqlXX-server

/etc/rc.conf.d/postgresql

postgresql_enable="YES"
#postgresql_data="/var/db/postgres"

初期化

# service postgresql initdb
または
# /usr/local/etc/rc.d/postgresql initdb
または
# mkdir /var/db/postgres
# chown postgres:postgres /var/db/postgres
# su - postgres
$ initdb -D /var/db/postgres/data

クライアント認証

/var/db/postgres/data/pg_hba.conf に設定します。
標準では自分自身からの接続のみを許可しています。

# TYPE  DATABASE        USER            CIDR-ADDRESS            METHOD
host    all             all             192.168.0.0/24          scram-sha-256

これで、192.168.0.xxxからの接続が許可されます。6)

ほかからアクセスする場合には、postgresql.confのlisten_addresses も変更が必要です。

listen_addresses = '*'

起動

# service postgresql start

password変更

root(postgres)ユーザのパスワードを変更します。7)

alter role postgres with password 'xxxxxxxxxxxxxxxxxxxx';

Role(ユーザ)の追加

# su - postgres
$ createuser -d -U postgres -P ユーザー名
Enter password for new role: 
Enter it again: 
Shall the new role be a superuser? (y/n) 

-d
データベースの作成を許可

-P
パスワード入力プロンプトを表示

または、psqlの中で

CREATE ROLE role_name WITH LOGIN PASSWORD 'password'

ユーザの一覧

# psql postgres

postgres=# \du
                             List of roles
 Role name | Superuser | Create role | Create DB | Connections | Member of 
-----------+-----------+-------------+-----------+-------------+-----------
 dbuser1   | no        | no          | no        | no limit    | {}
 dbuser2   | no        | no          | no        | no limit    | {}
 postgres  | yes       | yes         | yes       | no limit    | {}
(3 rows)
postgres=# 

パスワード変更

# psql postgres

postgres=# alter role postgres with password 'NewPassword';
ALTER ROLE
postgres=# 

データベースの作成

$ createdb -E UTF8 -O オーナー名 データベース名

私は、面倒なのでpgadminから作っています。;-)

SQLの場合

CREATE DATABASE [database_name]
    [ [ WITH ] [ OWNER [=] user_name ]
           [ TEMPLATE [=] template ]
           [ ENCODING [=] encoding ]
           [ LC_COLLATE [=] lc_collate ]
           [ LC_CTYPE [=] lc_ctype ]
           [ TABLESPACE [=] tablespace_name ]
           [ CONNECTION LIMIT [=] connlimit ] ]

文字コードが標準と違う場合には

TEMPLATE = template0

を指定する必要があります8)

日本語DBの作成例

CREATE DATABASE dbname WITH OWNER ownername 
  ENCODING UTF8 LC_COLLATE 'ja_JP.UTF-8' LC_CTYPE 'ja_JP.UTF-8'
  TEMPLATE template0
;

なお、localeはエンコーディング部分はUTF8ではなくてUTF-8となります。マニュアルなどにはハイフンなしで書かれていますがハイフンが必要です。9)

AutoVacuum

デフォルトの設定では、自動バキュームは有効で、関連するパラメータも適切に設定されています。 10)11)

参考

1)
再起動後に反映
2)
2026-04-28: FreeBSD pkgでは'–without-icu'でビルドされているので注意
3) , 6)
scram-sha-256は暗号化パスワード接続
4) , 7)
パスワードは別紙参照
5)
少し古い
8)
必須です
9)
FreeBSDで確認したので、Linuxでは違うかもしれません。マニュアルにも環境依存と書かれていますし…
10)
9.0.x
serverapps/db/postgresql.1777305509.txt.gz · 最終更新: by hayashi