kei0425tan’s blog

技術的なことを主に

PostgreSQLのtemplate0,template1,postgresとかバックアップとか

仕事でPostgreSQLを利用しているのですが、いろいろと理解できていなかったところがあったので、その中でもtemplate0,template1,postgresについて

template0とtemplate1の違いについて

template1

createdb実行時に-Tで指定しない場合はデフォルトで雛形として利用されます。
雛形のため、template1を変更しても、変更以前に作成されたDBにはその変更は適用されません。
変更後に作成したDBには同じ変更が適用されます。

主に、コードセットの設定や、拡張コマンドなどをいれるとよいでしょう。
テーブルなども作成しておくことは可能ですが、あまり有効な利用方法は思いつきません。

template0

PostgreSQLの最低限必要もののみが設定されています。
変更はできません。
余計な変更が入っていると困る場合は、createdb実行時に-T template0を指定します。

posgres(DB名)について

デフォルトのDB名。qsqlなどコマンドで接続先を指定しない場合に利用されます。
サードパーティのユーティリティも、postgresDBに接続していろいろなコマンドを実行することが多いです。
削除はできません。

initdbについて

initdbを実行すると、まずtemplate1が作成されて、それをtemplate0とpostgresにコピーします。
マニュアルを読むと、template0を雛形にしてtemplate1が作成されるとありますが、実際には上記の順番で作成。
ただし、実質initdbした直後はtemplate0とtemplate1は同一のため、それほど気にする必要はなさそうです。

initdb /tmp/posttestを実行したログ

The files belonging to this database system will be owned by user "postgres".
This user must also own the server process.

The database cluster will be initialized with locale "en_US.UTF-8".
The default database encoding has accordingly been set to "UTF8".
The default text search configuration will be set to "english".

Data page checksums are disabled.

creating directory /tmp/posttest ... ok
creating subdirectories ... ok
selecting default max_connections ... 100
selecting default shared_buffers ... 128MB
creating configuration files ... ok
creating template1 database in /tmp/posttest/base/1 ... ok
initializing pg_authid ... ok
initializing dependencies ... ok
creating system views ... ok
loading system objects' descriptions ... ok
creating collations ... ok
creating conversions ... ok
creating dictionaries ... ok
setting privileges on built-in objects ... ok
creating information schema ... ok
loading PL/pgSQL server-side language ... ok
vacuuming database template1 ... ok
copying template1 to template0 ... ok
copying template1 to postgres ... ok
syncing data to disk ... ok

WARNING: enabling "trust" authentication for local connections
You can change this by editing pg_hba.conf or using the option -A, or

    • auth-local and --auth-host, the next time you run initdb.

Success. You can now start the database server using:

/usr/local/pgsql/bin/postgres -D /tmp/posttest
or
/usr/local/pgsql/bin/pg_ctl -D /tmp/posttest -l logfile start

バックアップ pg_dump について

バックアップファイルには、そのDB作成時に利用したテンプレートの内容も含まれます。

https://www.postgresql.jp/document/9.3/html/backup-dump.html#BACKUP-DUMP-RESTORE

重要項目: pg_dumpで作成されるダンプはtemplate0と相対関係にあります。 つまりtemplate1を経由して追加されたあらゆる言語、プロシージャなどもpg_dumpによりダンプされます。 その結果としてリストアする際に、カスタマイズされたtemplate1を使用している場合は、上記の例のように、template0から空のデータベースを作成する必要があります。

DBをリストアする場合に、事前にDBを作成してリストアする場合には
template0を利用しないと、template1の変更点が重複するため、template0を利用するのがおすすめのようです。

https://www.postgresql.jp/document/9.3/html/app-pgrestore.html

template1データベースに対し独自の変更を行っている場合、pg_restoreの出力は、確実に空のデータベースにロードするよう注意してください。 そうしないと、おそらく追加されたオブジェクトの重複定義によってエラーが発生します。 独自の追加が反映されていない空のデータベースを作成するには、template1ではなくtemplate0をコピーしてください。 以下に例を示します。

リストア時には、新規データベースにて、template1で使えるようにした拡張コマンドがそのままでは利用できなくなります。

バックアップ pg_dumpallについて

pg_dumpallでは、以下をバックアップします。

  • 各ロール、ユーザ
  • 各ユーザ追加DB
  • template1の変更点
  • postgres(DB)の変更点
各ユーザ追加DB

バックアップファイルには、create database -T template0で作成するようになっています。
そのため、リストアした新規データベースでは、リストア前にtemplate1に対して行った変更は反映されません。

template1,postgres

バックアップファイルには、create databaseはなく、変更点のみになっています。
そのため、リストアした新規データベースでは、リストア前にtemplate1に対して行った変更はそのままで、さらに、バックアップ元で行った変更が行われます。
よって、拡張コマンドなどはそのまま利用できます。

POH8「恋するハッカソン〜君色に染まるアイドル」 「制服」ゲットチャレンジ!

ランクB相当だそうです。

最初適当にさらさらっと書いたら、なかなかうまく動作しなかったため、ちょっと真面目に書いてみました。
わざわざクラスまで作成するのもどうかなーと思いつつ、pythonだとハッシュが面倒なのでクラス化しています。

paiza D007:N倍の文字列

初めて1位を取れました!

paiza.jp

まあ、Dランクなので以下に速く問題を理解して(全部読む必要はない)キーを打つのか勝負なんですけどね。
あとは、タイトルでどんな問題なのか想像して、それに適した言語を選ぶのがポイントです。

codingame ASCII Art

久しぶりに、codingameをやってみました。

codingame.com


超意訳で問題説明してみます。

アスキーアートを作ろう

入力

Line 1: the width L of a letter represented in ASCII art. All letters are the same width.
1行目はアスキーアートの幅です。全部の文字は同じ幅です。Lとします。
Line 2: the height H of a letter represented in ASCII art. All letters are the same height.
2行目はアスキーアートの高さです。全部の文字は同じ高さです。Hとします。
Line 3: The line of text T, composed of N ASCII characters.
3行目はアスキーアートに変換する文字です。Tとします。
Following lines: the string of characters ABCDEFGHIJKLMNOPQRSTUVWXYZ? Represented in ASCII art.
その後ろには、ABCDEFGHIJKLMNOPQRSTUVWXYZ?のアスキーアートの元ネタです。

出力

The text T in ASCII art.
入力のTをアスキーアートにしてください。
The characters a to z are shown in ASCII art by their equivalent in upper case.
小文字a-zは大文字に変換してください。
The characters that are not in the intervals [a-z] or [A-Z] will be shown as a question mark in ASCII art.
アルファベット以外の場合は?のアスキーアートにしてください。

そんなわけでpythonで書いてみました。

import sys
import math

# Auto-generated code below aims at helping you parse
# the standard input according to the problem statement.

l = int(raw_input())
h = int(raw_input())
t = raw_input()
rows = [raw_input() for i in xrange(h)]

# Write an action using print
# To debug: print >> sys.stderr, "Debug messages..."
def convert(x):
    c = ord(x.upper()) - 65
    if c < 0 or 25 < c:
        c = 26
    return c

indexes = [convert(x) for x in t]

for row in rows:
    print ''.join([row[l * i:l * i + l] for i in indexes])

アスキーアートの元ネタを変換して持たせようかとも思いましたが、pythonの場合はそのまま保持していてもスライス表記で簡単に扱えるため、変換せず。
一方、アルファベット以外は逆に事前に変換しています。

paiza B032:デジタル計算機

ヒントにならないように感想のみで。


まずは基本情報


paiza B032:デジタル計算機
受験者数: 291人 正解率: 70.48% 平均回答時間: 53分25秒 平均スコア: 58.45点

いいスコアをとりたかったので、受験者数が少なめ。
面倒な問題はやなので、平均回答時間短め。
平均スコアが低めなものは罠がある場合が多いけど、慎重にやれば大丈夫かな??

で、特定言語マスターを埋めようと思い、現在はPython2のみなので、それ以外の言語縛りでーと思い、最近勉強中のScalaで解こうと思い問題をみましたが、ちょっと難しそうだぞということで、JavaScriptで解きました。

で、結果。
paiza.jp

受験結果 受験言語: JavaScript 回答時間: 38分36秒 バイト数: 1581 Byte スコア: 50点

半分間違えてしまいました。
回答時間はかなり早めだったんですが。。。。

何を間違えたのかなーって思ったのですが、全然無視してた条件がありました。

そう思って、いろいろ調べた結果、どうやらJavaScriptを選択した時点でこの結果は決まっていたようです。
Pythonにしておけば、問題なかったのになぁ・・・・

やはり、例のみではなく、自分でエッジのテストはしないと100点はとれないですね。

ちなみに、Rubyでも同様の制限があるようです。

JavaScriptでもbigintを利用すればまだなんとかなるようです。
※ そもそも「デジタル計算機」であって「○○リーダー、○○ライター」ではないってことに気が付かなきゃいけなかったんですね。

JavaScriptで末尾再帰で素数

今度は、JavaScriptで末尾再帰を利用して素数を取得してみました。

paiza.ioでは処理時間が2秒が上限のため、700000まで取得できました。
スタックオーバーフローはおきませんでした。

末尾再帰とは

関数の末尾が自分自身の呼び出しのみになっている再帰のこと。
ここでいう末尾とは、関数の最後の行ということではなく、処理の末尾のこと。(普通はreturn文)


意味のないコードですが、以下のようなものが末尾再帰になります。

function f(x) {
   if (x == 0) {
      return 1;
   }
   return f(x - 1);
}

以下は階乗を取得する再帰関数ですが、最後が自分自身の呼び出しのみになっていないため、末尾再帰ではありません。

function fact(x) {
   if (x == 1) {
      return 1;
   }
   return x * fact(x - 1);
}

なんで、わざわざ再帰でも末尾再帰と特別な名前がついているのかといいますと、簡単に末尾再帰最適化ができるからです。
これは、コンパイラが自動的に対応する場合もありますし、手でも簡単にできます。

JavaScriptには末尾再帰最適化の機能がES6で導入されたため、まだ実装されている処理系はあまりありません。
paiza.ioのNode.jsも未対応です。

なので、手で末尾再帰最適化を行ってみましょう。

問題のコードはこちら

function prime(n) {
    var limit = Math.sqrt(n);
    
    function primemain(primelist, remain) {
        if (remain.length === 0) {
            return primelist;
        }
        else if (limit < remain[0]) {
            return primelist.concat(remain);
        }
        else {
            primelist.push(remain[0]);
            return primemain(primelist, remain.filter(function (x) {return x % remain[0] !== 0}));
        }
    }
    
    var remain = [];
    for (var i = 2; i < n + 1; i++) {
        remain.push(i);
    }

    return primemain([], remain);
}

末尾再帰最適化したコードはこちら。

function prime(n) {
    var limit = Math.sqrt(n);
    var primelist = [];
    var remain = [];
    for (var i = 2; i < n + 1; i++) {
        remain.push(i);
    }
    
    while (true) {
        if (remain.length === 0) {
            return primelist;
        }
        else if (limit < remain[0]) {
            return primelist.concat(remain);
        }
        else {
            primelist.push(remain[0]);
            remain = remain.filter(function (x) {return x % remain[0] !== 0});
        }
    }
}

以下の手順で変更します。

  1. 関数定義前に、パラメータだった変数を初期化
  2. 関数定義を無限ループに変更。
  3. 再帰呼び出し箇所で、パラメータを修正するように変更。

実際に動作するものは以下になります。

せっかく直したのにほとんど速度は変わりませんでした。

※ paiza.ioで、「don't make functions within a loop」のワーニングがでていますが、このケースではクロージャでないため、問題ありません。(クロージャで遅延評価をする場合は危険)
※ 通常の再帰を末尾再帰に変換するほうが大変です。