私の作業用として、よく使うSQLやTIPS、トラブルシューティング的なものをまとめました。
SQL
データベース操作
バージョン確認
SELECT * FROM version();
データベース一覧
select * from pg_database;
データベース作成
-- ユーザ作成
create role user_name with superuser login password 'password';
-- データベース削除
drop database database_name;
-- データベース作成
create database database_name
with owner user_name
template template0
encoding 'UTF8'
lc_collate 'C'
lc_ctype 'C'
;
- 文字コードセットはUTF8
- lc_collage(文字の照合順序)、lc_ctype(大文字・小文字・数字の分類)に「C」を指定しています
- この場合、文字の照合順序は文字コードのバイナリ順、分類は大文字・小文字を分けて処理されるようになります
- 「ja_JP.UTF-8」のように言語を指定できますが、その場合は文字の照合順序が文字順、分類は大文字・小文字を区別しないようになります
- パフォーマンスも若干下がるようです
データベースのサイズ確認
select datname, pg_size_pretty(pg_database_size(datname)) from pg_database;
登録されている拡張機能の一覧確認
SELECT * FROM pg_available_extensions;
ユーザー操作
ユーザー一覧確認
select * from pg_user;
テーブル操作
テーブル一覧(行数+サイズ)確認
SELECT * FROM information_schema.tables WHERE table_catalog = 'database_name';
SELECT
t.table_name
, pc.reltuples AS row_num
, (pc.relpages * 8192) AS byte_size
FROM
information_schema.tables t
INNER JOIN pg_class pc
ON pc.relname = t.table_name
WHERE
t.table_catalog = 'database_name'
AND t.table_schema = 'public'
AND t.table_name NOT LIKE '\_%'
ORDER BY
t.table_name
;
select句からテーブル作成
CREATE TABLE new_table_name AS SELECT * FROM old_table_name;
インデックス操作
そのうち書きます
カラム操作
カラム一覧の確認
SELECT
c.*
FROM
information_schema.tables t
INNER JOIN information_schema.columns c
ON c.table_catalog = t.table_catalog
AND c.table_schema = t.table_schema
AND c.table_name = t.table_name
WHERE
t.table_catalog = 'database_name'
AND t.table_name = 'table_name'
ORDER BY
t.table_name
, c.ordinal_position
ストアドプロシージャ操作
無名のコードブロック
無名コードブロック
do $$declare
-- 変数宣言
BEGIN
-- 処理コード
END;$$
無名のコードブロック(サンプル)
do $$declare
-- 変数定義
c_loganalyze cursor (p_logtype VARCHAR) IS
SELECT filename, seq, logtype, message
FROM LogAnalyze
WHERE logtype = p_logtype
;
v_rec record;
v_fields CHARACTER VARYING(256)[]; -- MESSAGE列をスペースで区切った配列
BEGIN
-- heapログのMESSAGE列に対して、スペースで分割しField1~4までデータを更新していく
FOR v_rec IN c_loganalyze('vmstat') loop
-- スペースで区切った配列をそれぞれのフィールドに格納
v_fields := regexp_split_to_array(v_rec.message, E'\ +');
-- ここまでで切り出した各FIELD用の変数を用いてUpdate
UPDATE
LogAnalyze
SET
field1 = v_fields[3],
field2 = v_fields[4],
field3 = v_fields[5],
field4 = v_fields[6],
field5 = v_fields[7],
field6 = v_fields[8],
field7 = v_fields[9],
field8 = v_fields[10],
field9 = v_fields[11],
field10 = v_fields[12],
field11 = v_fields[13],
field12 = v_fields[14],
field13 = v_fields[15],
field14 = v_fields[16],
field15 = v_fields[17],
field16 = v_fields[18]
WHERE
filename = v_rec.filename AND
seq = v_rec.seq AND
logtype = v_rec.logtype
;
END loop;
END;$$
SELECT
そのうち書きます
INSERT
INSERT INTO table_name (
column_3
, column_4
)
SELECT
column_1
, column_2
FROM
table_name_1
;
UPDATE
UPDATE table_name SET column_name = 'value' WHERE KEY = 1;
UPDATE main_table
SET
column1 = jt1.column1
FROM main_table a
LEFT OUTER JOIN join_table_1 jt1
ON jt1.key = a.key
WHERE
a.key = main_table.key
AND a.key = 1
;
- PostgreSQLのupdate joinの制約
- 更新対象のテーブル(update句の後に続くテーブル)に対してjoinをつけることができないようです
- 更新対象のテーブルにエイリアスをつけてもset句の中で使うことができません
- https://www.postgresql.jp/document/12/html/sql-update.html
- column_name
- table_nameで指名されたテーブル内の列名です。 必要に応じて、列名を副フィールド名や配列の指示子で修飾することも可能です。 対象列の指定にはテーブル名を含めないでください。 たとえば、UPDATE table_name SET table_name.col = 1は無効です。
- column_name
- https://www.postgresql.jp/document/12/html/sql-update.html
- select文のようにfrom句を指定しそこにjoinでテーブルを結合できますが、そのままではupdate句のテーブルと何の関係もなくなってしまいます
- つまり全件更新されてしまいます
- MySQL等からのSQL移植
- updateのターゲットテーブルをfrom句に追加、エイリアスも
- その下にjoinたちを移動
- update xxxx alias のaliasは削除、set句の中にある更新対象テーブルのエイリアスを削除
- where句にupdateのターゲットテーブルとfromのキーの結合条件を追加(しないと全テーブル更新されるためです)
DELETE
DELETE
FROM
table_name
WHERE
KEY = 1
コマンド
psql
pgdumpコマンドで出力したスクリプトをpsqlコマンドで実行
-- ファイルをリダイレクトで読み込み実行
psql -h localhost -U postgres -p 5432 -d database_name < backup.sql
-- -fオプションで実行
psql -h localhost -U postgres -p 5432 -d database_name -f backup.sql
- psqlではコマンドラインオプションでパスワードを指定できませんが、パスワードファイルを用意しておくことで実行可能となります
- Windows
- ファイル %APPDATA%\postgresql\pgpass.conf 作成
- 上記ファイルに「hostname:port:database:username:password」を記載し保存
- Linux
- homeディレクトリに.pgpassファイルを作成
- 上記ファイルに「hostname:port:database:username:password」を記載し保存
- Windows
- 環境変数にパスワードやユーザー名を設定することも可能です
- set PGUSER=xxx
- set PGPASSWORD=xxx
- set PGHOSTNAME=xxx
- set PGPORT=xxx
- set PGDATABASE=xxx
- 読み込むSQLファイルがUTF8の場合は環境変数で文字コードを指定します
- set PGCLIENTENCODING=UTF8
ファイルにあるSQLを実行してCSV出力
psql -h localhost -U postgres -p 5432 -d database_name -f test.sql -A -F"," -o output.csv
- -A:均等割り付けを行わない
- -F:フィールドセパレータ、タブを指定したい場合はctrl-vの後にタブキー入力
TSVエクスポートは以下で可能
psql -h localhost -U postgres -p 5432 -c "copy(select * from table_name) to stdout with csv delimiter E'\t' quote E'\b' null as '' header ;" database_name > table_name.txt
pgdump
エクスポート
-- リダイレクトでエクスポート
pg_dump -h localhost -U postgres database_name > backup.sql
-- -fオプションでファイルを指定しエクスポート
pg_dump -f backup.sql -h localhost -U postgres database_name
テーブルを指定してエクスポート
pg_dump -t table_name -f backup.sql -c -h localhost -p 5432 -U user_name database_name
vacuumdb
vacuumdb -U postgres database_name [option]
- -full
- FULL実行
- -v
- 詳細な情報を出力
パフォーマンスチェック/チューニング
SQLの確認
そのうち書きます
チューニング
そのうち書きます
TIPS
ログの出力先をsyslogに変更
log_destination = 'stderr,syslog'
syslog_facility = 'LOCAL0'
syslog_ident = 'postgres'
syslog_sequence_numbers = on
syslog_split_messages = on
log_min_messages = info
- PostgreSQLはログの出力先を複数持てます
- log_destinationにカンマ区切りで記載できるそうです
- 設定反映にはデーモンの再起動が必要です
- sudo systemctl restart postgresql-13 sudo systemctl status postgresql-13
- エラーログが出力されているかどうかは、サーバー上でpsqlのログインにパスワード入力で失敗すれば分かります
- sudo su – postgres -c “psql”
PostgreSQLのzipファイルを使用してインストール
こちらから「Binaries from installer Version xx.x」をダウンロードします
zipファイルを展開し以下のフォルダを作成(以下はC:\pgsqlに展開した例)
- C:\pgsql
- data
- log
initdbを実行しスーパーユーザーを作成します
C:\WINDOWS\system32>initdb -U postgres -W -A password -D C:\pgsql\data --encoding=UTF8
データベースシステム内のファイルの所有者はユーザ"xxxxxx"となります。
このユーザをサーバプロセスの所有者とする必要があります。
データベースクラスタはロケール"Japanese_Japan.932"で初期化されます。
initdb: could not find suitable text search configuration for locale "Japanese_Japan.932"
デフォルトのテキスト検索構成は simple に設定されます。
データベージのチェックサムは無効です。
新しいスーパユーザのパスワードを入力してください:
再入力してください:
ディレクトリC:/pgsql/dataの権限を設定しています ... ok
サブディレクトリを作成しています ... ok
動的共有メモリの実装を選択しています ... windows
デフォルトのmax_connectionsを選択しています ... 100
デフォルトの shared_buffers を選択しています ... 128MB
selecting default time zone ... Asia/Tokyo
設定ファイルを作成しています ... ok
ブートストラップスクリプトを実行しています ... ok
ブートストラップ後の初期化を実行しています ... ok
データをディスクに同期しています ... ok
成功しました。以下のようにしてデータベースサーバを起動することができます:
pg_ctl -D ^"C^:^\pgsql^\data^" -l ログファイル start
postgres のパスワードを忘れた時
pg_hba.conf を探してMETHODの指定をpassword→trustに変更します。(ファイルはdataディレクトリにあると思います)
# TYPE DATABASE USER ADDRESS METHOD
# IPv4 local connections:
host all all 127.0.0.1/32 password
# IPv6 local connections:
host all all ::1/128 password
# Allow replication connections from localhost, by a user with the
# replication privilege.
host replication all 127.0.0.1/32 password
host replication all ::1/128 password
- trustはパスワードなしで接続OKの設定です
PostgreSQLを再起動し、psqlでログイン後にパスワードを変更します。
C:\Windows\system32> psql -h localhost -U postgres
psql (12.4)
"help"でヘルプを表示します。
postgres=#
postgres=# \password
postgres=# alter role postgres with password 'new password';
postgres=# \q
編集したpg_hba.confを元に戻してPostgreSQLを再起動します。
SQLSTATE[42804]: Datatype mismatch: 7 ERROR: UNIONの型textとintegerを一致させることができません
PostgreSQLでは3つ以上のunionをする場合、先頭のSQLで指定されたnull as xxxxはTEXT型と判断されてしまうようです。
以下がエラーの発生する例です。
SELECT NULL AS col
UNION
SELECT NULL AS col
UNION
SELECT 1 AS col
;
- 1・2番目のcolはnullですが、3番目のcolは数値なのでtext型にできずエラーとなってしまいます
型の分かるselectを先に持ってくることで対応可能です。
SELECT 1 AS col
UNION
SELECT NULL AS col
UNION
SELECT NULL AS col
;