前回で実行計画も見れるようになったので実際にベンチマークをとっていく。
PostgreSQL上でのベンチマークをとる準備その2 - gos-k’s blog
前提としてこれは私がDBを知らないから試しているのであって、まともに勉強している人にとって新しい情報は何も出てこないと思う。
以前作ったレコード数100万だと少なそうな気がしたので1億に増やす。 中断もあり出来上がりまで2日くらいかかった。
runとexplを再定義する。
(ql:quickload '(:cl-dbi :sxql)) (defvar *connection* (dbi:connect :postgres :database-name "test" :username "myuser" :password "1234")) (defun run (sxql &key silent) (multiple-value-bind (sql binds) (sxql:yield sxql) (let ((query (dbi:execute (dbi:prepare *connection* sql) binds))) (unless silent (format t "~{~S~%~}" (dbi:fetch-all query)))))) (defun expl (sxql &key silent analyze verbose) (multiple-value-bind (sql binds) (sxql:explain sxql :analyze analyze :verbose verbose) (let ((query (dbi:execute (dbi:prepare *connection* sql) binds))) (unless silent (format t "~{~A~%~}" (mapcar #'second (dbi:fetch-all query)))))))
単純にレコード数を数える時間の計測。
(time (run (sxql:select ((:count :*)) (sxql:from :bench1))))
(:|count| 100000000) Evaluation took: 28.944 seconds of real time 0.076228 seconds of total run time (0.068817 user, 0.007411 system) 0.26% CPU 130 lambdas converted 75,019,658,522 processor cycles 9,039,856 bytes consed
28.944秒。結構時間かかるが短すぎると計測出来ないのでまあとりあえずこんなもんで。レコード数1000万でも良かったかもしれないが。
もう一度実行する。
(time (run (sxql:select ((:count :*)) (sxql:from :bench1))))
(:|count| 100000000) Evaluation took: 2.516 seconds of real time 0.008230 seconds of total run time (0.007765 user, 0.000465 system) 0.32% CPU 34 lambdas converted 6,527,313,242 processor cycles 851,184 bytes consed
今度は2.516秒。一桁速いので何らかキャッシュが効いてそうだが、それなりなので同一SQLはLUTを引くような速さではなさそう。
その後何度か実行するが大きくは変わらず。
インデックスの有無
現状のインデックスを確認。
(run (sxql:select (:tablename :indexname) (sxql:from :pg_indexes) (sxql:where (:not (:like :tablename "pg_%")))))
PostgreSQL側のインデックスしかないので何も表示されない。 プライマリキーにはデフォルトでインデックスつくような話があった気がするが、そういえばテーブルの定義にプライマリつけてなかった。
インデックスなしで計測
uuidをソートして(そんなことしても普通実用的な意味は無いが)値が大きいものを取り出す。
(time (run (sxql:select (:*) (sxql:from :bench1) (sxql:order-by (:desc :uuid)) (sxql:limit 1))))
(:|uuid| "FFFFFFF4-3400-4E53-B670-F09C03D7CB9B" :|int_data| 35 :|real_data| 81.5925) Evaluation took: 11.179 seconds of real time 0.001657 seconds of total run time (0.001657 user, 0.000000 system) 0.02% CPU 28,971,618,296 processor cycles 59,888 bytes consed
取得に11.179秒。
uuidを指定して取得。
(time (run (sxql:select (:*) (sxql:from :bench1) (sxql:where (:= :uuid "FFFFFFF4-3400-4E53-B670-F09C03D7CB9B")))))
(:|uuid| "FFFFFFF4-3400-4E53-B670-F09C03D7CB9B" :|int_data| 35 :|real_data| 81.5925) Evaluation took: 2.380 seconds of real time 0.001368 seconds of total run time (0.001191 user, 0.000177 system) 0.04% CPU 6,171,428,638 processor cycles 32,784 bytes consed
取得に2.380秒。
インデックスありで計測
とりあえずbench1のuuidに関するインデックスを作る。
(time (run (sxql:create-index :bench1_uuid_index :on '(:bench1 :uuid))))
Evaluation took: 320.967 seconds of real time 0.009390 seconds of total run time (0.000000 user, 0.009390 system) 0.00% CPU 831,940,213,012 processor cycles 67,120 bytes consed
再び1つ取り出す。
(time (run (sxql:select (:*) (sxql:from :bench1) (sxql:order-by (:desc :uuid)) (sxql:limit 1))))
(:|uuid| "FFFFFFF4-3400-4E53-B670-F09C03D7CB9B" :|int_data| 35 :|real_data| 81.5925) Evaluation took: 0.000 seconds of real time 0.003648 seconds of total run time (0.003148 user, 0.000500 system) 100.00% CPU 5,614,760 processor cycles 65,520 bytes consed
計測できないほど速くなった。
uuid指定も同様に。
(time (run (sxql:select (:*) (sxql:from :bench1) (sxql:where (:= :uuid "FFFFFFF4-3400-4E53-B670-F09C03D7CB9B")))))
(:|uuid| "FFFFFFF4-3400-4E53-B670-F09C03D7CB9B" :|int_data| 35 :|real_data| 81.5925) Evaluation took: 0.012 seconds of real time 0.000978 seconds of total run time (0.000853 user, 0.000125 system) 8.33% CPU 24,829,884 processor cycles 0 bytes consed
こちらは時間計測できて実行時間が100分の1以下となった。
(:|uuid| "FFFFFFF4-3400-4E53-B670-F09C03D7CB9B" :|int_data| 35 :|real_data| 81.5925) Evaluation took: 0.000 seconds of real time 0.000803 seconds of total run time (0.000698 user, 0.000105 system) 100.00% CPU 5,650,996 processor cycles 32,544 bytes consed
2回目実行したら計測不能。
計測不能なので実行計画を見る。
(expl (sxql:select (:*) (sxql:from :bench1) (sxql:where (:= :uuid "FFFFFFF4-3400-4E53-B670-F09C03D7CB9B"))))
Index Scan using bench1_uuid_index on bench1 (cost=0.57..8.59 rows=1 width=45) Index Cond: ((uuid)::text = 'FFFFFFF4-3400-4E53-B670-F09C03D7CB9B'::text)
ないものを探す。
(time (run (sxql:select (:*) (sxql:from :bench1) (sxql:where (:= :uuid "dummy")))))
Evaluation took: 0.004 seconds of real time 0.000635 seconds of total run time (0.000526 user, 0.000109 system) 25.00% CPU 3,656,096 processor cycles 0 bytes consed
0.004秒。
索引のない整数について50以下を取り出す。
(time (run (sxql:select ((:count :*)) (sxql:from :bench1) (sxql:where (:< :int_data 50)) (sxql:group-by :int_data) (sxql:order-by (:desc :int_data)))))
Evaluation took: 30.532 seconds of real time 0.028304 seconds of total run time (0.023632 user, 0.004672 system) 0.09% CPU 156 lambdas converted 79,134,651,138 processor cycles 9,826,656 bytes consed
30.532秒。 2回目の実行。
Evaluation took: 4.743 seconds of real time 0.007597 seconds of total run time (0.007597 user, 0.000000 system) 0.17% CPU 34 lambdas converted 12,290,504,776 processor cycles 851,200 bytes consed
大分速くなって4.743秒。
整数に索引をつける。
(time (run (sxql:create-index :bench1_int_data_index :on '(:bench1 :int_data))))
Evaluation took: 62.028 seconds of real time 0.004582 seconds of total run time (0.004582 user, 0.000000 system) 0.01% CPU 34 lambdas converted 160,772,178,188 processor cycles 726,208 bytes consed
62.028秒。 索引ありで整数の50以下を取り出す。
(time (run (sxql:select ((:count :*)) (sxql:from :bench1) (sxql:where (:< :int_data 50)) (sxql:group-by :int_data) (sxql:order-by (:desc :int_data)))))
Evaluation took: 4.316 seconds of real time 0.005106 seconds of total run time (0.000328 user, 0.004778 system) 0.12% CPU 0 processor cycles End of buffer consed
4.316秒。あまり変わらない。同一のクエリに対して索引相当のキャッシュが作られる?
実数の50.0以下を取り出す。
(time (run (sxql:select ((:count :*) :real_data) (sxql:from :bench1) (sxql:where (:< :real_data 50.0)) (sxql:group-by :real_data) (sxql:order-by (:asc :real_data)))))
Evaluation took: 11.135 seconds of real time 0.730950 seconds of total run time (0.633282 user, 0.097668 system) 6.56% CPU 28,859,121,622 processor cycles 446,585,280 bytes consed
11.135秒。2回目。
Evaluation took: 11.651 seconds of real time 0.738516 seconds of total run time (0.701032 user, 0.037484 system) [ Run times consist of 0.109 seconds GC time, and 0.630 seconds non-GC time. ] 6.34% CPU 30,196,880,508 processor cycles 1 page fault 436,348,768 bytes consed
11.651秒。整数の一回目が遅いのが何か特殊?
索引を実数につける。
(time (run (sxql:create-index :bench1_real_data_index :on '(:bench1 :real_data)))
Evaluation took: 88.633 seconds of real time 0.017629 seconds of total run time (0.016032 user, 0.001597 system) 0.02% CPU 229,724,215,970 processor cycles 1,568,528 bytes consed
索引ありで実数の50.0以下を取り出す。
(time (run (sxql:select ((:count :*) :real_data) (sxql:from :bench1) (sxql:where (:< :real_data 50.0)) (sxql:group-by :real_data) (sxql:order-by (:asc :real_data)))))
Evaluation took: 12.112 seconds of real time 0.632849 seconds of total run time (0.613674 user, 0.019175 system) 5.23% CPU 31,400,792,736 processor cycles 435,509,344 bytes consed
12.112秒。索引の効果がない。
selectを実行するとそのキャッシュが出来る仕組みなんだろうか?
とりあえず何も分からないこということが分かった。