PostgreSQL上でのベンチマークをとる準備

DB全般をあまり知らないので、仕事上使っているPostgreSQL上で簡単なベンチマークをとる。

PostgresSQLの準備

https://www.postgresql.jp/document/12/html/tutorial-start.html ローカルにPostgresSQLをインストールする。

psqlからデータベースを作る。

createdb test

練習用ロールを作る。

CREATE USER "myuser" CREATEDB PASSWORD '1234';

cl-dbiでのアクセス

cl-dbiで対象dbに接続する。

(ql:quickload :cl-dbi)                               
(defvar *connection*
  (dbi:connect :postgres                             
               :database-name "test"                                                                      
               :username "myuser"                    
               :password "1234"))  

実行用の関数を定義する。

(defun run (string &key params silent)                                                                    
  (let ((query (dbi:execute (dbi:prepare *connection*
                                         string)                                                         
                            params)))
    (unless silent
      (loop for row = (dbi:fetch query)
            while row
            do (pprint row)))))

テーブルを作る。

(time (run "CREATE TABLE bench1 (uuid varchar(36), int_data int, real_data real);"))

データを登録する。

(run "INSERT INTO bench1 VALUES (?, ?, ?);"
     :params (list (print-object (uuid:make-v4-uuid) nil) (random 100) (random 100.0))
     :silent t)

1つデータを見る。

(run "SELECT * FROM bench1 LIMIT 1;" ) ;; (:|uuid| "9D9624B4-9275-4F67-8754-B8F27710D77C" :|int_data| 31 :|real_data| 31.218767)

データ数を見る。

(run "SELECT COUNT(*) FROM bench1;" ) ;; (:|count| 1000)

ベンチマーク用データ追加

ちょっとした問題として、SELECTのベンチマークをとるためにデータのINSERTを100万回くらい行おうとすると途中でheap exhaustedとなる。 どこかでメモリーリークがあるみたいだが、よく分からないがとりあえずヒープ最大を20GBくらいに増やす。

ros config set dynamic-space-size 20000

10万回は通ったのでこれで何度か実行する。

(time (dotimes (_ 100000)
        (run "INSERT INTO bench1 VALUES (?, ?, ?);"
             :params (list (print-object (uuid:make-v4-uuid) nil) 
                           (random 100)
                           (random 100.0))
             :silent t)))

10万回ループのデータ登録を10回実行する。 10万回あたりだいたい145秒かかった。

SxQLの導入

SQLを文字列で埋め込んでいくのも面倒なのでSxQLを導入する。

(ql:quickload :sxql)

(defun run (sxql &key silent)
  (multiple-value-bind (sql binds) (sxql:yield sxql)
    (pprint sql)
    (let ((query (dbi:execute (dbi:prepare *connection*
                                           sql)
                              binds)))
      (unless silent
        (loop for row = (dbi:fetch query)                     
              while row
              do (pprint row))))))

レコードの全数カウント。

(time (run (sxql:select ((:count :*))
             (sxql:from :bench1))))