[PostgreSQL] テンプレートDBに関する考察 | A Day In The Boy's Life

A Day In The Boy's Life

とあるエンジニアのとある1日のつぶやき。

普段あまり意識する事はありませんが、PostgreSQLにはデータふぃある初期化(initdb実行時)に3つのDBが作成されます。


template0

template1

postgres


この上2つのtemplateXというDBは、全てのDBのテンプレートとなるDBという特殊な意味を持っています。

これについては、マニュアルの中にも触れられて(@ PostgreSQL 8.3.3文書) いますが、もう少し詳しくみていってみます。


どういうことかは、具体的に動かしてみればはっきり分かります。


例)

$ psql template1
template1=# create table master (id integer, name text);
CREATE TABLE
template1=# \z
Access privileges for database "template1"
Schema | Name | Type | Access privileges
--------+------ +-----+-------------------
public | master | table |
(1 row)
template1=# \q
$ createdb testdb
CREATE DATABASE
$ psql testdb
testdb=# \z
Access privileges for database "testdb"
Schema | Name | Type | Access privileges
--------+------+------+-------------------
public | master | table |
(1 row)

どうでしょう。

template1で作成したテーブル(master)が、その後に作ったDBであるtestdb上でも勝手に作られています。

このように、template1は全てのDBのテンプレートとなる役割を果たしています。


template1がこういう用途のDBとなっているため、template1内にオブジェクトを作ってはならないとなっています。

作ってしまった場合、その後作る全DBにそのオブジェクトがコピーされて作られてしまうためです。


※ 全DBで共通のテーブルを作成したい場合(本番DBとテストDBの用途分けなど)などに意味を持ったりしますが、

  それほど大きな用途としてはなさそうな気もします。


では、次にtemplate0の役割です。

こちらも、同じテンプレートDBですがtemplate0へは接続する事もできません。


$ psql template0
psql: FATAL: database "template0" is not currently accepting connections 


こちらは、マニュアルに書いてあるとおりで、データファイル初期化時(initidb実行時)の状態のテンプレートDBとなっています。(純粋な状態のテンプレートDB)

template1のDBへは接続や変更を加える事はできますが、template0へは(通常のままだと)変更を加える事や接続する事はできません。

template0はtemplate1のテンプレートにもなっています。(言い方が紛らわしいですが)


予断となりますが、残り一つのpostgresというDBですが、こちらもinitdb実行時に自動的に作成されるDBです。


$ initdb
(snip)
copying template1 to template0 ... ok
copying template1 to postgres ... ok


次に、マニュアルをよく読むとtemplate1は削除する事ができると書いていますが、実際に削除してみるとエラーが出てしまいます。


$ dropdb template1
dropdb: database removal failed: ERROR: cannot drop a template database

誤ってtemplate1内にオブジェクトを作ってしまった場合、一つ一つのオブジェクトを削除するのも面倒なので、ばっさりとDBごとを削除してしまいたいと考えるかもしれません。

(template1は削除してもよいものと、マニュアルにも記載されています)


具体的にtemplate1のDBを削除するには、下記の方法を取れば可能です。


$ psql template1
template1=# UPDATE pg_database SET datistemplate = FALSE where datname = 'template1';
UPDATE 1
template1=# \q
$ dropdb template1
DROP DATABASE 

まず、pg_database というシステムカタログ(Oracleのデータディクショナリのようなもの)内にある、「datistemplate」というカラムをFALSEにセットします。

このカラムは、テンプレートに指定ができるかどうかを表すもので、template1ではデフォルトTRUEになっています。

datistemplateカラムがTRUEとなっている場合、DBの削除は行えません。


template1を再作成したい場合、引き続き下記の操作を行います。


$ createdb template1 --template=template0;
CREATE DATABASE
$ psql -l
List of databases
Name | Owner | Encoding
-----------+----------+----------
postgres   | postgres | UTF8
template0  | postgres | UTF8
template1  | postgres | UTF8
(3 rows)
$ psql template1
template1=# UPDATE pg_database SET datistemplate = TRUE where datname = 'template1';
UPDATE 1

template1は、全DBのテンプレートとなる特殊なDBという意味からも、勝手に削除をされないように、再度UPDATEをかけて元の状態に戻しています。


ただ、このような回りくどいやり方をせずとも、バックアップを取るべきDBをpg_dumpコマンドでバックアップし、initdbでデータファイルを初期化後に、リストアするという方法もあります。

ただし、pg_dumpallで取得したバックアップファイルからリストアする場合、template1も対象となっているので気をつけましょう。