MAGAZINE
ルーターマガジン
PostgreSQLのスキーマ作成とsearch_path設定の実践例(MySQLユーザー向け)
ルーターエンジニアのtoyamaです。今回はポスグレのスキーマについてです。
ずっとMySQLを使ってきたため、PostgreSQLのスキーマについてあまり理解せずつかっていたのですが、ようやく理解できてきたので情報をまとめておきたいと思います。
スキーマとは、データベースの中にさらにグループを作ることができる機能で、異なるスキーマの下に同じ名前のテーブルなどをつくることができます。
以下、実例を交えながら説明していきます。
データベースの作成
まず例としてtest_dbというデータベースを作成してみます。
$ psql -U postgres
postgres=# CREATE DATABASE test_db;
作成したら早速、test_dbに接続して、スキーマ一覧を確認しましょう。
\cでデータベースの切り替え、\dnで現在接続しているデータベースのスキーマをみれます。
postgres=# \c test_db
test_db=# \dn
List of schemas
Name | Owner
--------+-------------------
public | pg_database_owner
(1 row)
スキーマは特に作成していないのにpublicというスキーマが作成されています。
これはデータベース作成時にスキーマを指定しない場合デフォルトで作成されるスキーマです。
スキーマの作成
続いてtest_dbにtest_schemaという名前のスキーマを作成してみましょう。
ここでスキーマはデータベースの下に作られることに注意してください。
ポスグレへの接続時、データベースを指定しない場合、postgresというデータベースに接続します。
postgeesに接続した状態でスキーマを作成すると、postgresデータベースの下にスキーマが作られてしまいます。
なので、DBを指定してログインするか、ログイン後にDBを切り替えましょう。
$ psql -U postgres -d test_db
または
$ psql -U postgres
postgres=# \c test_db
test_db=# CREATE SCHEMA test_schema;
CREATE SCHEMA
test_db=# \dn
List of schemas
Name | Owner
-------------+-------------------
public | pg_database_owner
test_schema | postgres
無事test_schemが作成されました。
では続いて、idのみのテストテーブルを作成してみましょう。
test_db=# CREATE TABLE test_table (id bigint);
CREATE TABLE
test_db=# \dt
List of relations
Schema | Name | Type | Owner
--------+------------+-------+----------
public | test_table | table | postgres
publicスキーマにtest_tableが作成されました。
ではtest_schemaにテーブルを作成する場合はどうすればよいでしょうか?
簡単なやり方として主に2つあります。
-
修飾語を使う
テーブル名の前に「スキーマ名.」をつけることでスキーマを指定できます。 MySQLでデータベースを指定するときに使用していたやり方ですね。test_db=# CREATE TABLE test_schema.test_table (id bigint); CREATE TABLE test_db=# \dt test_schema.* List of relations Schema | Name | Type | Owner -------------+------------+-------+---------- test_schema | test_table | table | postgres (1 row)
-
search_pathを設定する
search_pathとは、1つ目の方法でスキーマを指定しなかったときに接続するスキーマを決定する設定値です。 現在のsearch_pathはshow search_path;で確認できます。
search_pathのデフォルト値は"$user", publicで”$user”は現行ユーザを表します。psql -U postgresの場合は$userの値はpostgresになります。
下の場合、クエリ中に修飾語による指定がない場合、postgresスキーマ、publicスキーマの順に評価されていきます。このため最初にテーブルを作成したときにpostgresスキーマはないため、publicスキーマにテーブルが作成されたのです。test_db=# show search_path; search_path ----------------- "$user", public (1 row)
search_pathはset search_path TO スキーマ名1,スキーマ名2…;という形で変更できます。これはセッション終了とともにデフォルトにもどります。
test_db=# set search_path = test_schema; SET test_db=# show search_path; search_path ------------- test_schema (1 row) # 再ログイン test_db=# \q test_db=# show search_path; search_path ----------------- "$user", public (1 row)
この設定を行ったセッション内であれば、修飾語がなくてもtest_shemaスキーマに対してテーブル作成などを行うことができます。
test_db=# CREATE TABLE test_table (id bigint); CREATE TABLE test_db=# \dt List of relations Schema | Name | Type | Owner -------------+------------+-------+---------- test_schema | test_table | table | postgres (1 row)
実験
test_schema,publicの2つのスキーマにtest_tableがある状態ですが、ここでsearch_pathに両方を指定した場合どんな挙動になるか調べてみました。
test_db=# set search_path = test_schema,public;
SET
test_db=# \dt
List of relations
Schema | Name | Type | Owner
-------------+------------+-------+----------
test_schema | test_table | table | postgres
(1 row)
test_db=# show search_path;
search_path
---------------------
test_schema, public
(1 row)
test_db=# set search_path = public,test_schema;
SET
test_db=# \dt
List of relations
Schema | Name | Type | Owner
--------+------------+-------+----------
public | test_table | table | postgres
(1 row)
同じテーブルが存在する場合、search_pathの最初で指定されたスキーマのテーブルで評価されていることがわかります。 2つのテーブルを1つのクエリで指定したいときは、修飾語を使わないといけないようです。
test_db=# select * from test_table
join test_schema.test_table
on public.test_table.id = test_schema.test_table.id
;
id | id
----+----
(0 rows)
search_pathの初期値の変更方法
-
postgresql.cnfで設定する サーバーの設定ファイルで設定できますが、すべてのDBで設定されてしまうのでおすすめできないです。
#search_path = '"$user",public' # schema names
-
ALTER DATABASEで設定する ALTER DATABASE文でそのデータベースに対して、search_pathのデフォルトを設定できます。 もしschemaを複数作った場合は、以下のように「,」で並列に設定できます。
test_db=# ALTER DATABASE test_db set search_path = test_schema,public; ALTER DATABASE # 一度ログアウト test_db=# \q $ psql -U postgres -d test_db test_db=# show search_path; search_path --------------------- test_schema, public (1 row) # 設定値の確認 test_db=# select pd.datname, pdrs.setconfig from pg_catalog.pg_db_role_setting pdrs join pg_catalog.pg_database pd on pdrs.setdatabase = pd.oid ; datname | setconfig ---------+------------------------------------- test_db | {"search_path=test_schema, public"} (1 row)
まとめ
MySQLと同じイメージで使うなら、特にスキーマは作成せず、デフォルトのpublicを使うのが一番しっくりきそうです。
もし自分でスキーマを作成してポスグレを使うなら、修飾語やsearch_pathの認識は必須ですね。
この記事でポスグレのスキーマのイメージを掴んでくれれば幸いです。
CONTACT
お問い合わせ・ご依頼はこちらから