今まで適当にPostgreSQLを使ってきたので、学び直しの意味も兼ねて「完全攻略 PostgreSQL: 現場で使える最強データベース入門 」という書籍を読みました。
振り返りとして、自分なりにPostgreSQLの各種機能や使い方をまとめてみます。
作業リポジトリはこちら:
データベース・スキーマ・ユーザーの関係性
PostgreSQLサーバー
|- データベース (Database)
| |- スキーマ (Schema)
| |- テーブル (Table)
| |- ビュー (View)
| |- 関数 (Function)
| |- インデックス (Index)
|- ユーザー (User/Role)
データベースの概念
PostgreSQLにおけるデータベースは、データの集合とその管理環境を指します。
1つのPostgreSQLサーバーには複数のデータベースを作成でき、各データベースは独立したデータ管理領域を持ちます。データベース間で直接テーブルやデータを共有することはできません。
特徴
- 独立性: データベース間は完全に独立しており、スキーマやテーブルは共有されない
- アクセス制御: 接続ユーザーごとにアクセスできるデータベースを制限可能
- 用途分離: 開発環境、本番環境、テスト環境などで異なるデータベースを作成し、運用できる。
-- データベースの作成
CREATE DATABASE sample_db;
-- データベース一覧
\l
スキーマの概念
スキーマはデータベース内のオブジェクト(テーブル、ビュー、関数、インデックスなど)を整理する名前空間です。
スキーマで名前空間を分けることで、同じ名前のテーブルを複数作成することができます。
PostgreSQLにはデフォルトで public というスキーマが存在し、データベース作成時に自動で付与されます。複雑な設計の場合、用途別にスキーマを分割することが推奨されます。
例:
-
public汎用的なテーブル -
sales売上関連データ -
hr人事関連データ
-- スキーマの作成
CREATE SCHEMA sales;
-- スキーマの確認
\dn
/*
List of schemas
Name | Owner | Access privileges | Description
--------+-------------------+----------------------------------------+------------------------
public | pg_database_owner | pg_database_owner=UC/pg_database_owner+| standard public schema
| | =U/pg_database_owner |
sales | app | |
(2 rows)
*/
-- スキーマを指定してテーブルを作成
CREATE TABLE IF NOT EXISTS sales.orders (
id SERIAL PRIMARY KEY,
order_date DATE NOT NULL,
amount NUMERIC(10, 2) NOT NULL
);
スキーマを追加しただけだと、スキーマが検索パス(search_path) に含まれていないため、\d などの一覧に表示されません。
\d
/*
List of relations
Schema | Name | Type | Owner
--------+--------------+----------+-------
public | users | table | app
public | users_id_seq | sequence | app
(2 rows)
*/
スキーマ名.* をつけると表示されます。
\d sales.*
/*
Table "sales.orders"
Column | Type | Collation | Nullable | Default
------------+---------------+-----------+----------+------------------------------------------
id | integer | | not null | nextval('sales.orders_id_seq'::regclass)
order_date | date | | not null |
amount | numeric(10,2) | | not null |
Indexes:
"orders_pkey" PRIMARY KEY, btree (id)
Sequence "sales.orders_id_seq"
Type | Start | Minimum | Maximum | Increment | Cycles? | Cache
---------+-------+---------+------------+-----------+---------+-------
integer | 1 | 1 | 2147483647 | 1 | no | 1
Owned by: sales.orders.id
Index "sales.orders_pkey"
Column | Type | Key? | Definition
--------+---------+------+------------
id | integer | yes | id
primary key, btree, for table "sales.orders"
*/
もしくは、検索パスに sales スキーマを追加することで表示されるようになります。
※ 検索パスはテーブル名が指定されたときにどのスキーマから探すかというリストです。 (ログインするたびに設定が必要なので、 .psqlrc に書いておくと良い))
-- 現在の検索パスの設定を表示
SHOW search_path;
-- search_path
-- -----------------
-- "$user", public
-- (1 row)
-- 検索パスにsalesを追加
SET search_path TO sales, public;
-- SET
SHOW search_path;
-- search_path
-- ---------------
-- sales, public
-- (1 row)
-- salesスキーマ内のテーブルが表示される
\d
-- List of relations
-- Schema | Name | Type | Owner
-- --------+---------------+----------+-------
-- public | users | table | app
-- public | users_id_seq | sequence | app
-- sales | orders | table | app
-- sales | orders_id_seq | sequence | app
-- (4 rows)
ユーザーの概念
PostgreSQLにおけるユーザー(あるいはロール) は、データベースへの接続や操作の権限を持つ主体です。
ユーザーはログイン可能なロールとして定義され、必要に応じて権限を付与できます。
一般的なユーザーの作成
CREATE ROLE readonly_user WITH LOGIN PASSWORD 'hogehoge';
CREATE ROLE app_user WITH LOGIN PASSWORD 'hogehoge';
CREATE ROLE dev_user WITH LOGIN PASSWORD 'hogehoge';
ユーザー一覧の確認
\du
/*
Role name | Attributes
---------------+------------------------------------------------------------
admin_user | Superuser
app | Superuser, Create role, Create DB, Replication, Bypass RLS
app_user |
dev_user |
readonly_user |
*/
ユーザーへの権限付与
-- 読み取り専用ユーザー
GRANT CONNECT ON DATABASE sample TO readonly_user;
GRANT USAGE ON SCHEMA public TO readonly_user;
GRANT SELECT ON ALL TABLES IN SCHEMA public TO readonly_user;
-- アプリケーションユーザー(CRUD操作)
GRANT CONNECT ON DATABASE sample TO app_user;
GRANT USAGE ON SCHEMA public TO app_user;
GRANT SELECT, INSERT, UPDATE, DELETE ON ALL TABLES IN SCHEMA public TO app_user;
GRANT USAGE ON ALL SEQUENCES IN SCHEMA public TO app_user;
-- 開発者ユーザー(オブジェクト作成も可能)
GRANT CONNECT ON DATABASE sample TO dev_user;
GRANT USAGE, CREATE ON SCHEMA public TO dev_user;
GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA public TO dev_user;
特権ユーザーの作成
SUPERUSERができること:
- すべての権限チェックをバイパス
- ほかユーザーのオブジェクトを操作・削除
- データベースの作成・削除
- ロールの作成・削除
- レプリケーションの設定
- 設定ファイルの再読み込み
- すべてのテーブル・スキーマへのアクセス
-- 既存ユーザーにSUPERUSER属性を付与
ALTER ROLE test_user SUPERUSER;
-- 新規作成時にSUPERUSER属性を付与
CREATE ROLE admin_user WITH LOGIN SUPERUSER PASSWORD 'hogehoge';
SUPERUSER以外の特権属性について
SUPERUSER以外の特権属性には以下のようなものがあります。
ALTER ROLE admin_user WITH
SUPERUSER -- すべての権限チェックをバイパス
CREATEDB -- データベースを作成できる
CREATEROLE -- ロールを作成できる
REPLICATION -- レプリケーション接続ができる
BYPASSRLS; -- Row Level Securityをバイパス
特権属性の確認 (pg_roles)
ユーザーに付与した特権属性は pg_roles テーブルから確認できます。
SELECT * FROM pg_roles WHERE rolname NOT LIKE 'pg_%';
/*
rolname | rolsuper | rolinherit | rolcreaterole | rolcreatedb | rolcanlogin | rolreplication | rolconnlimit | rolpassword | rolvaliduntil | rolbypassrls | rolconfig | oid
---------------+----------+------------+---------------+-------------+-------------+----------------+--------------+-------------+---------------+--------------+-----------+-------
...
admin_user | t | t | f | f | t | f | -1 | ******** | | f | | 16434
(5 rows)
*/
権限の確認
データベースに対する権限の確認 (pg_database)
書式 grantee=権限/grantor:
| エントリ | grantee | 権限 | grantor | 解釈 |
|---|---|---|---|---|
=Tc/app |
PUBLIC(全員) | T, c | app | TEMPORARY, CONNECT |
app=CTc/app |
app | C, T, c | app | CREATE, TEMPORARY, CONNECT |
readonly_user=c/app |
readonly_user | c | app | CONNECT |
app_user=c/app |
app_user | c | app | CONNECT |
dev_user=c/app |
dev_user | c | app | CONNECT |
SELECT datname, datacl FROM pg_database WHERE datname = 'sample';
/*
-[ RECORD 1 ]--------------------------------------------------------------------
datname | sample
datacl | {=Tc/app,app=CTc/app,readonly_user=c/app,app_user=c/app,dev_user=c/app}
*/
スキーマに対する権限の確認 (pg_namespace)
書式 grantee=権限/grantor:
| エントリ | grantee (被権限付与者) |
権限 | grantor (権限付与者) |
|---|---|---|---|
pg_database_owner=UC/pg_database_owner |
pg_database_owner | U (USAGE), C (CREATE) | pg_database_owner |
=U/pg_database_owner |
全員 | U (USAGE) | pg_database_owner |
readonly_user=U/pg_database_owner |
readonly_user | U (USAGE) | pg_database_owner |
app_user=U/pg_database_owner |
app_user | U (USAGE) | pg_database_owner |
dev_user=UC/pg_database_owner |
dev_user | U (USAGE), C (CREATE) | pg_database_owner |
SELECT nspname, nspacl FROM pg_namespace WHERE nspname = 'public';
/*
-[ RECORD 1 ]-------------------------------------------------------------------------------------------------------------------------------------------------------
nspname | public
nspacl | {pg_database_owner=UC/pg_database_owner,=U/pg_database_owner,readonly_user=U/pg_database_owner,app_user=U/pg_database_owner,dev_user=UC/pg_database_owner}
*/
テーブルに対する権限の確認 (information_schema.table_privileges)
SELECT
grantee,
table_catalog,
table_schema,
table_name,
string_agg(privilege_type, ', ')
FROM
information_schema.table_privileges
WHERE
grantee = 'dev_user'
GROUP BY
grantee, table_catalog, table_schema, table_name;
/*
-[ RECORD 1 ]-+--------------------------------------------------------------
grantee | dev_user
table_catalog | sample
table_schema | public
table_name | users
string_agg | INSERT, SELECT, UPDATE, DELETE, TRUNCATE, REFERENCES, TRIGGER
*/
各オブジェクトに対する権限のまとめ
データベース(DATABASE)
| 権限 | 説明 |
|---|---|
| CONNECT | データベースに接続する。これがないとログインできない |
| CREATE | データベース内に新しいスキーマを作成する |
| TEMPORARY / TEMP | 一時テーブルを作成する |
| ALL / ALL PRIVILEGES | すべての権限 |
スキーマ(SCHEMA)
※ 自ユーザーが作成したスキーマに対しては自動的に全権限を持ちます。他のユーザーが作成したスキーマを操作したい場合に権限設定が必要になります。
| 権限 | 説明 |
|---|---|
| USAGE | スキーマ内のオブジェクトにアクセスする。これがないとスキーマ内のテーブル等が見えない |
| CREATE | スキーマ内に新しいオブジェクト(テーブル、関数など)を作成する |
| ALL / ALL PRIVILEGES | すべての権限 |
テーブル(TABLE)
| 権限 | 説明 |
|---|---|
| SELECT | テーブルの任意の列から行を読み取る。COPY TOの使用にも必要 |
| INSERT | テーブルに新しい行を挿入する。COPY FROMの使用にも必要 |
| UPDATE | テーブルの行を更新する。実際にはSELECTも必要になることが多い(WHERE句で列を参照するため) |
| DELETE | テーブルから行を削除する。同様にSELECTが必要になることが多い |
| TRUNCATE | テーブルの全行を高速に削除する(DELETEより速いがロールバック不可) |
| REFERENCES | このテーブルを参照する外部キー制約を作成する |
| TRIGGER | このテーブルにトリガーを作成する |
| ALL / ALL PRIVILEGES | すべての権限 |
シーケンス(SEQUENCE)
| 権限 | 説明 |
|---|---|
| USAGE |
currvalとnextval関数を使用する(採番) |
| SELECT |
currval関数を使用する(現在値の取得のみ) |
| UPDATE |
setval関数を使用する(値のリセットや調整(管理用)) |
| ALL / ALL PRIVILEGES | すべての権限 |
関数・プロシージャ(FUNCTION / PROCEDURE)
| 権限 | 説明 |
|---|---|
| EXECUTE | 関数やプロシージャを実行する。デフォルトでPUBLICに付与されている |
| ALL / ALL PRIVILEGES | すべての権限 |
型(TYPE)
| 権限 | 説明 |
|---|---|
| USAGE | 型をテーブル列の定義や関数の引数・戻り値として使用する。デフォルトでPUBLICに付与されている |
| ALL / ALL PRIVILEGES | すべての権限 |
テーブルスペース(TABLESPACE)
| 権限 | 説明 |
|---|---|
| CREATE | このテーブルスペース内にテーブル、インデックス、一時ファイルを作成する |
| ALL / ALL PRIVILEGES | すべての権限 |
ラージオブジェクト(LARGE OBJECT)
| 権限 | 説明 |
|---|---|
| SELECT | ラージオブジェクトを読み取る |
| UPDATE | ラージオブジェクトに書き込む(上書き含む) |
| ALL / ALL PRIVILEGES | すべての権限 |
外部データラッパー(FOREIGN DATA WRAPPER)
| 権限 | 説明 |
|---|---|
| USAGE | このラッパーを使用して外部サーバーを作成する |
| ALL / ALL PRIVILEGES | すべての権限 |
外部サーバー(FOREIGN SERVER)
| 権限 | 説明 |
|---|---|
| USAGE | このサーバーを使用して外部テーブルやユーザーマッピングを作成する |
| ALL / ALL PRIVILEGES | すべての権限 |