PostgreSQL 8.1 の count(*) を高速化


PostgreSQL 8.1 で count(*) の取得が遅いので高速化してみた。

↓高速化対応前


ec_shop=> EXPLAIN ANALYZE SELECT count(*) FROM order WHERE is_settled = 't' AND delete_flag = 'f';
                                                         QUERY PLAN
-----------------------------------------------------------------------------------------------------------------------------
 Aggregate  (cost=146378.16..146378.17 rows=1 width=0) (actual time=3108.970..3108.971 rows=1 loops=1)
   ->  Seq Scan on order  (cost=0.00..144762.80 rows=646145 width=0) (actual time=0.241..3091.596 rows=21089 loops=1)
         Filter: (is_settled AND (NOT delete_flag))
 Total runtime: 3109.115 ms
(4 rows)



↓高速化対応後


ec_shop=> EXPLAIN ANALYZE SELECT count(*) FROM order WHERE id > 0 AND is_settled = 't' AND delete_flag = 'f';
                                                                        QUERY PLAN
----------------------------------------------------------------------------------------------------------------------------------------------------------
 Aggregate  (cost=133584.15..133584.17 rows=1 width=0) (actual time=540.989..540.990 rows=1 loops=1)
   ->  Bitmap Heap Scan on order  (cost=8744.16..133045.70 rows=215382 width=0) (actual time=311.333..524.769 rows=21089 loops=1)
         Recheck Cond: (id > 0)
         Filter: (is_settled AND (NOT delete_flag))
         ->  Bitmap Index Scan on order_idx_is_settled  (cost=0.00..8744.16 rows=430763 width=0) (actual time=306.146..306.146 rows=21092 loops=1)
               Index Cond: ((id > 0) AND (is_settled = true))
 Total runtime: 541.263 ms
(7 rows)



INDEX を利用しているカラムを指定(上の例では id )する事で検索するレコード行数を制限した。
結果、検索する行数が減って結果の表示が速くなった。


↓参考
https://wiki.postgresql.org/wiki/Slow_Counting/ja
https://www.postgresql.jp/document/8.1/html/performance-tips.html


こういうのパズルみたいで楽しい。