PostgreSQLの便利クエリの動作確認③

2024-09-09

PostgreSQL

PostgreSQL

この記事は前回の続きです。

https://master—pea-sys-blog.netlify.app/posts/20240908/

PostgreSQLバージョンの数値表現を取得します

dvdrental=# SHOW server_version_num;
 server_version_num
--------------------
 160002
(1 行)

テーブルの肥大化を検出します

dvdrental=# -- Credit: https://github.com/ioguix/pgsql-bloat-estimation/tree/master/table
dvdrental=# -- minor tweaks to exclude pg tables
dvdrental=# /* WARNING: executed with a non-superuser role, the query inspect only tables and materialized view (9.3+) you are granted to read.
dvdrental*# * This query is compatible with PostgreSQL 9.0 and more
dvdrental*# */
dvdrental-# SELECT current_database(), schemaname, tblname, bs*tblpages AS real_size,
dvdrental-#   (tblpages-est_tblpages)*bs AS extra_size,
dvdrental-#   CASE WHEN tblpages - est_tblpages > 0
dvdrental-#     THEN 100 * (tblpages - est_tblpages)/tblpages::float
dvdrental-#     ELSE 0
dvdrental-#   END AS extra_pct, fillfactor,
dvdrental-#   CASE WHEN tblpages - est_tblpages_ff > 0
dvdrental-#     THEN (tblpages-est_tblpages_ff)*bs
dvdrental-#     ELSE 0
dvdrental-#   END AS bloat_size,
dvdrental-#   CASE WHEN tblpages - est_tblpages_ff > 0
dvdrental-#     THEN 100 * (tblpages - est_tblpages_ff)/tblpages::float
dvdrental-#     ELSE 0
dvdrental-#   END AS bloat_pct, is_na
dvdrental-#   -- , tpl_hdr_size, tpl_data_size, (pst).free_percent + (pst).dead_tuple_percent AS real_frag -- (DEBUG INFO)
dvdrental-# FROM (
dvdrental(#   SELECT ceil( reltuples / ( (bs-page_hdr)/tpl_size ) ) + ceil( toasttuples / 4 ) AS est_tblpages,
dvdrental(#     ceil( reltuples / ( (bs-page_hdr)*fillfactor/(tpl_size*100) ) ) + ceil( toasttuples / 4 ) AS est_tblpages_ff,
dvdrental(#     tblpages, fillfactor, bs, tblid, schemaname, tblname, heappages, toastpages, is_na
dvdrental(#     -- , tpl_hdr_size, tpl_data_size, pgstattuple(tblid) AS pst -- (DEBUG INFO)
dvdrental(#   FROM (
dvdrental(#     SELECT
dvdrental(#       ( 4 + tpl_hdr_size + tpl_data_size + (2*ma)
dvdrental(#         - CASE WHEN tpl_hdr_size%ma = 0 THEN ma ELSE tpl_hdr_size%ma END
dvdrental(#         - CASE WHEN ceil(tpl_data_size)::int%ma = 0 THEN ma ELSE ceil(tpl_data_size)::int%ma END
dvdrental(#       ) AS tpl_size, bs - page_hdr AS size_per_block, (heappages + toastpages) AS tblpages, heappages,
dvdrental(#       toastpages, reltuples, toasttuples, bs, page_hdr, tblid, schemaname, tblname, fillfactor, is_na
dvdrental(#       -- , tpl_hdr_size, tpl_data_size
dvdrental(#     FROM (
dvdrental(#       SELECT
dvdrental(#         tbl.oid AS tblid, ns.nspname AS schemaname, tbl.relname AS tblname, tbl.reltuples,
dvdrental(#         tbl.relpages AS heappages, coalesce(toast.relpages, 0) AS toastpages,
dvdrental(#         coalesce(toast.reltuples, 0) AS toasttuples,
dvdrental(#         coalesce(substring(
dvdrental(#           array_to_string(tbl.reloptions, ' ')
dvdrental(#           FROM 'fillfactor=([0-9]+)')::smallint, 100) AS fillfactor,
dvdrental(#         current_setting('block_size')::numeric AS bs,
dvdrental(#         CASE WHEN version()~'mingw32' OR version()~'64-bit|x86_64|ppc64|ia64|amd64' THEN 8 ELSE 4 END AS ma,

dvdrental(#         24 AS page_hdr,
dvdrental(#         23 + CASE WHEN MAX(coalesce(s.null_frac,0)) > 0 THEN ( 7 + count(s.attname) ) / 8 ELSE 0::int END
dvdrental(#            + CASE WHEN bool_or(att.attname = 'oid' and att.attnum < 0) THEN 4 ELSE 0 END AS tpl_hdr_size,
dvdrental(#         sum( (1-coalesce(s.null_frac, 0)) * coalesce(s.avg_width, 0) ) AS tpl_data_size,
dvdrental(#         bool_or(att.atttypid = 'pg_catalog.name'::regtype)
dvdrental(#           OR sum(CASE WHEN att.attnum > 0 THEN 1 ELSE 0 END) <> count(s.attname) AS is_na
dvdrental(#       FROM pg_attribute AS att
dvdrental(#         JOIN pg_class AS tbl ON att.attrelid = tbl.oid
dvdrental(#         JOIN pg_namespace AS ns ON ns.oid = tbl.relnamespace
dvdrental(#         LEFT JOIN pg_stats AS s ON s.schemaname=ns.nspname
dvdrental(#           AND s.tablename = tbl.relname AND s.inherited=false AND s.attname=att.attname
dvdrental(#         LEFT JOIN pg_class AS toast ON tbl.reltoastrelid = toast.oid
dvdrental(#       WHERE NOT att.attisdropped
dvdrental(#         AND tbl.relname not like '%pg%'
dvdrental(#         AND tbl.relkind in ('r','m')
dvdrental(#       GROUP BY 1,2,3,4,5,6,7,8,9,10
dvdrental(#       ORDER BY 2,3
dvdrental(#     ) AS s
dvdrental(#   ) AS s2
dvdrental(# ) AS s3
dvdrental-# -- WHERE NOT is_na
dvdrental-# --   AND tblpages*((pst).free_percent + (pst).dead_tuple_percent)::float4/100 >= 1
dvdrental-# ORDER BY bloat_pct DESC;
 current_database |     schemaname     |         tblname         | real_size | extra_size |     extra_pct      | fillfactor | bloat_size |     bloat_pct      | is_na
------------------+--------------------+-------------------------+-----------+------------+--------------------+------------+------------+--------------------+-------
 dvdrental        | public             | film                    |    720896 |     303104 |  42.04545454545455 |        100 |     303104 |  42.04545454545455 | f
 dvdrental        | public             | city                    |     40960 |       8192 |                 20 |        100 |       8192 |                 20 | f
 dvdrental        | public             | address                 |     65536 |       8192 |               12.5 |        100 |       8192 |               12.5 | f
 dvdrental        | public             | customer                |     73728 |       8192 |  11.11111111111111 |        100 |       8192 |  11.11111111111111 | f
 dvdrental        | public             | rental                  |   1228800 |     131072 | 10.666666666666666 |        100 |     131072 | 10.666666666666666 | f
 dvdrental        | public             | category                |      8192 |          0 |                  0 |        100 |          0 |                  0 | f
 dvdrental        | public             | country                 |      8192 |          0 |                  0 |        100 |          0 |                  0 | f
 dvdrental        | public             | film_actor              |    245760 |          0 |                  0 |        100 |          0 |                  0 | f
 dvdrental        | public             | film_category           |     49152 |          0 |                  0 |        100 |          0 |                  0 | f
 dvdrental        | public             | inventory               |    204800 |          0 |                  0 |        100 |          0 |                  0 | f
 dvdrental        | public             | language                |      8192 |          0 |                  0 |        100 |          0 |                  0 | f
 dvdrental        | public             | my_table                |         0 |          0 |                  0 |        100 |          0 |                  0 | t
 dvdrental        | public             | payment                 |    884736 |          0 |                  0 |        100 |          0 |                  0 | f
 dvdrental        | public             | staff                   |      8192 |          0 |                  0 |        100 |          0 |                  0 | f
 dvdrental        | public             | store                   |      8192 |          0 |                  0 |        100 |          0 |                  0 | f
 dvdrental        | information_schema | sql_features            |     65536 |          0 |                  0 |        100 |          0 |                  0 | f
 dvdrental        | public             | test                    |         0 |          0 |                  0 |        100 |          0 |                  0 | t
 dvdrental        | information_schema | sql_implementation_info |      8192 |          0 |                  0 |        100 |          0 |                  0 | f
 dvdrental        | information_schema | sql_parts               |      8192 |          0 |                  0 |        100 |          0 |                  0 | f
 dvdrental        | information_schema | sql_sizing              |      8192 |          0 |                  0 |        100 |          0 |                  0 | f
 dvdrental        | public             | actor                   |     16384 |          0 |                  0 |        100 |          0 |                  0 | f
(21 行)

テーブルを構成するデータの統計値を取得します

dvdrental=# SELECT
dvdrental-#     attname,
dvdrental-#     n_distinct,
dvdrental-#     most_common_vals,
dvdrental-#     most_common_freqs
dvdrental-# FROM
dvdrental-#     pg_stats
dvdrental-# WHERE
dvdrental-#     tablename = 'actor';
   attname   | n_distinct |
                                                                                                   most_common_vals     
                                                                   |
                                                                                       most_common_freqs


-------------+------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
 actor_id    |         -1 |


                                                                   |
 last_update |          1 | {"2013-05-26 14:47:57.62"}


                                                                   | {1}
 first_name  |      -0.64 | {Julia,Kenneth,Penelope,Burt,Cameron,Christian,Cuba,Dan,Ed,Fay,Gene,Groucho,Jayne,Matthew,Morgan,Nick,Russell,Adam,Albert,Angela,Audrey,Ben,Cate,Chris,Christopher,Daryl,Frances,Gary,Greta,Humphrey,Johnny,Kevin,Kirsten,Lucille,Mary,Mena,Meryl,Michael,Milla,Minnie,Reese,Renee,Rip,Sandra,Scarlett,Sean,Spencer,Susan,Tom,Vivien,Warren,Woody}                                                             | {0.02,0.02,0.02,0.015,0.015,0.015,0.015,0.015,0.015,0.015,0.015,0.015,0.015,0.015,0.015,0.015,0.015,0.01,0.01,0.01,0.01,0.01,0.01,0.01,0.01,0.01,0.01,0.01,0.01,0.01,0.01,0.01,0.01,0.01,0.01,0.01,0.01,0.01,0.01,0.01,0.01,0.01,0.01,0.01,0.01,0.01,0.01,0.01,0.01,0.01,0.01,0.01}
 last_name   |     -0.605 | {Kilmer,Nolte,Temple,Akroyd,Allen,Berry,Davis,Degeneres,Garland,Guiness,Harris,Hoffman,Hopkins,Johansson,Keitel,Peck,Torn,Williams,Willis,Zellweger,Bailey,Bening,Bolger,Brody,Cage,Chase,Crawford,Cronyn,Dean,Dee,Dench,Depp,Dukakis,Fawcett,Gooding,Hackman,Hopper,Jackman,Mcconaughey,Mckellen,Mcqueen,Monroe,Mostel,Neeson,Olivier,Paltrow,Penn,Silverstone,Streep,Tandy,Tracy,Wahlberg,West,Winslet,Wood} | {0.025,0.02,0.02,0.015,0.015,0.015,0.015,0.015,0.015,0.015,0.015,0.015,0.015,0.015,0.015,0.015,0.015,0.015,0.015,0.015,0.01,0.01,0.01,0.01,0.01,0.01,0.01,0.01,0.01,0.01,0.01,0.01,0.01,0.01,0.01,0.01,0.01,0.01,0.01,0.01,0.01,0.01,0.01,0.01,0.01,0.01,0.01,0.01,0.01,0.01,0.01,0.01,0.01,0.01,0.01}
(4 行)

指定したカラムが存在するテーブルを取得します

dvdrental=# -- credit: https://dataedo.com/kb/query/postgresql/find-tables-with-specific-column-name
dvdrental=# -- formatted to taste
dvdrental=# SELECT
dvdrental-#   t.table_schema,
dvdrental-#   t.table_name
dvdrental-# FROM
dvdrental-#   information_schema.tables t
dvdrental-#   INNER JOIN
dvdrental-#     information_schema.columns c
dvdrental-#     ON c.table_name = t.table_name
dvdrental-#     AND c.table_schema = t.table_schema
dvdrental-# WHERE
dvdrental-#   c.column_name = 'first_name'
dvdrental-#   AND t.table_schema NOT IN
dvdrental-#   (
dvdrental(#     'information_schema',
dvdrental(#     'pg_catalog'
dvdrental(#   )
dvdrental-#   AND t.table_type = 'BASE TABLE'
dvdrental-# ORDER BY
dvdrental-#   t.table_schema;
 table_schema | table_name
--------------+------------
 public       | customer
 public       | actor
 public       | staff
(3 行)

インデックスを使用する時間の割合を取得します

dvdrental=# -- https://www.craigkerstiens.com/2012/10/01/understanding-postgres-performance/
dvdrental=# SELECT
dvdrental-#     relname,
dvdrental-#     100 * idx_scan / (seq_scan + idx_scan) percent_of_times_index_used,
dvdrental-#     n_live_tup rows_in_table
dvdrental-# FROM
dvdrental-#     pg_stat_user_tables
dvdrental-# WHERE
dvdrental-#     seq_scan + idx_scan > 0
dvdrental-# ORDER BY
dvdrental-#     n_live_tup DESC;
    relname    | percent_of_times_index_used | rows_in_table
---------------+-----------------------------+---------------
 rental        |                           0 |         16044
 payment       |                          14 |         14596
 film_actor    |                           0 |          5462
 inventory     |                           0 |          4581
 film          |                           0 |          1000
 film_category |                           0 |          1000
 address       |                          50 |           603
 city          |                           0 |           600
 customer      |                           0 |           599
 actor         |                          22 |           200
 country       |                           0 |           109
 category      |                           0 |            16
 language      |                           0 |             6
 staff         |                          20 |             2
 store         |                           0 |             2
 my_table      |                           0 |             0
(16 行)

行数の多いテーブルトップ10を取得します

dvdrental=# SELECT
dvdrental-#     table_schema || '.' || table_name AS table_full_name,
dvdrental-#     reltuples::bigint AS row_count
dvdrental-# FROM
dvdrental-#     pg_class c
dvdrental-#     JOIN pg_namespace n ON n.oid = c.relnamespace
dvdrental-#     JOIN information_schema.tables t ON t.table_schema = n.nspname
dvdrental-#         AND t.table_name = c.relname
dvdrental-# WHERE
dvdrental-#     t.table_type = 'BASE TABLE'
dvdrental-#     AND t.table_schema NOT IN ('pg_catalog', 'information_schema', 'temp')
dvdrental-# ORDER BY
dvdrental-#     reltuples DESC
dvdrental-# LIMIT 10;
   table_full_name    | row_count
----------------------+-----------
 public.rental        |     16044
 public.payment       |     14596
 public.film_actor    |      5462
 public.inventory     |      4581
 public.film_category |      1000
 public.film          |      1000
 public.address       |       603
 public.city          |       600
 public.customer      |       599
 public.actor         |       200
(10 行)

サイズの大きいテーブルトップ10を取得します

dvdrental=# -- Top 10 largest by size, excluding some
dvdrental=# -- internal schemas
dvdrental=# SELECT
dvdrental-#     table_schema || '.' || table_name AS table_full_name,
dvdrental-#     pg_total_relation_size(table_schema || '.' || table_name) AS total_size,
dvdrental-#     pg_size_pretty(pg_total_relation_size(table_schema || '.' || table_name)) AS total_size_pretty
dvdrental-# FROM
dvdrental-#     information_schema.tables
dvdrental-# WHERE
dvdrental-#     table_type = 'BASE TABLE'
dvdrental-#     AND table_schema NOT IN ('pg_catalog', 'information_schema', 'temp')
dvdrental-# ORDER BY
dvdrental-#     pg_total_relation_size(table_schema || '.' || table_name) DESC
dvdrental-# LIMIT 10;
   table_full_name    | total_size | total_size_pretty
----------------------+------------+-------------------
 public.rental        |    2408448 | 2352 kB
 public.payment       |    1859584 | 1816 kB
 public.film          |     958464 | 936 kB
 public.film_actor    |     499712 | 488 kB
 public.inventory     |     450560 | 440 kB
 public.customer      |     212992 | 208 kB
 public.address       |     155648 | 152 kB
 public.film_category |     114688 | 112 kB
 public.city          |     114688 | 112 kB
 public.actor         |      73728 | 72 kB
(10 行)

UPDATEが多いテーブルトップ10を取得します

dvdrental=# -- top updated tables, including HOT updates
dvdrental=# -- https://medium.com/nerd-for-tech/postgres-fillfactor-baf3117aca0a
dvdrental=# SELECT
dvdrental-#     schemaname,
dvdrental-#     relname,
dvdrental-#     pg_size_pretty(pg_total_relation_size(relname::regclass)) AS full_size,
dvdrental-#     pg_size_pretty(pg_relation_size(relname::regclass)) AS table_size,
dvdrental-#     pg_size_pretty(pg_total_relation_size(relname::regclass) - pg_relation_size(relname::regclass)) AS index_size,
dvdrental-#     n_tup_upd,
dvdrental-#     n_tup_hot_upd
dvdrental-# FROM
dvdrental-#     pg_stat_user_tables
dvdrental-# ORDER BY
dvdrental-#     n_tup_upd DESC
dvdrental-# LIMIT 10;
 schemaname |  relname   | full_size  | table_size | index_size | n_tup_upd | n_tup_hot_upd
------------+------------+------------+------------+------------+-----------+---------------
 public     | customer   | 208 kB     | 72 kB      | 136 kB     |         0 |             0
 public     | country    | 24 kB      | 8192 bytes | 16 kB      |         0 |             0
 public     | film       | 936 kB     | 704 kB     | 232 kB     |         0 |             0
 public     | category   | 24 kB      | 8192 bytes | 16 kB      |         0 |             0
 public     | language   | 24 kB      | 8192 bytes | 16 kB      |         0 |             0
 public     | test       | 8192 bytes | 0 bytes    | 8192 bytes |         0 |             0
 public     | film_actor | 488 kB     | 240 kB     | 248 kB     |         0 |             0
 public     | rental     | 2352 kB    | 1200 kB    | 1152 kB    |         0 |             0
 public     | staff      | 32 kB      | 8192 bytes | 24 kB      |         0 |             0
 public     | my_table   | 16 kB      | 0 bytes    | 16 kB      |         0 |             0
(10 行)

デッドタプルが多いテーブルトップ10を取得します

dvdrental=# --- Viewing top tables with lots of dead tuples
dvdrental=# SELECT schemaname, relname, n_live_tup, n_dead_tup, last_autovacuum
dvdrental-# FROM pg_stat_all_tables
dvdrental-# where relname not like 'pg_%'
dvdrental-# ORDER BY n_dead_tup
dvdrental-#     / (n_live_tup
dvdrental(#        * current_setting('autovacuum_vacuum_scale_factor')::float8
dvdrental(#           + current_setting('autovacuum_vacuum_threshold')::float8)
dvdrental-#      DESC
dvdrental-# LIMIT 10;
     schemaname     |   relname    | n_live_tup | n_dead_tup |       last_autovacuum
--------------------+--------------+------------+------------+------------------------------
 information_schema | sql_sizing   |         23 |          0 |
 public             | country      |        109 |          0 |
 public             | actor        |        200 |          0 |
 public             | city         |        600 |          0 |
 public             | store        |          2 |          0 |
 public             | film         |       1000 |          0 |
 public             | category     |         16 |          0 |
 public             | payment      |      14596 |          0 | 2024-09-08 10:44:24.49724+09
 information_schema | sql_features |        756 |          0 |
 public             | customer     |        599 |          0 |
(10 行)

導入済みの拡張機能一覧を取得します

dvdrental=# -- e.g. SELECT extname,extversion FROM pg_extension;
dvdrental=# -- e.g. pg_stat_statements version
dvdrental=# SELECT * FROM pg_extension;
  oid  |      extname       | extowner | extnamespace | extrelocatable | extversion | extconfig | extcondition
-------+--------------------+----------+--------------+----------------+------------+-----------+--------------
 15049 | plpgsql            |       10 |           11 | f              | 1.0        |           |
 18249 | pg_stat_statements |       10 |         2200 | t              | 1.10       |           |
(2 行)

ロック解放待ちのクエリを取得します

dvdrental=# SELECT
dvdrental-#     pid,
dvdrental-#     wait_event_type,
dvdrental-#     wait_event,
dvdrental-#     LEFT (query,
dvdrental(#         60) AS query,
dvdrental-#     backend_start,
dvdrental-#     query_start,
dvdrental-#     (CURRENT_TIMESTAMP - query_start) AS ago
dvdrental-# FROM
dvdrental-#     pg_stat_activity
dvdrental-# WHERE
dvdrental-#     datname = 'dvdrental';
  pid  | wait_event_type | wait_event |                            query                             |         backend_start         |          query_start          |       ago
-------+-----------------+------------+--------------------------------------------------------------+-------------------------------+-------------------------------+-----------------
 20228 |                 |            | SELECT                                                      +| 2024-09-08 19:03:08.967448+09 | 2024-09-08 19:43:00.712825+09 | 00:00:00
       |                 |            |     pid,                                                    +|
             |                               |
       |                 |            |     wait_event_type,                                        +|
             |                               |
       |                 |            |     wait_event,                                             +|
             |                               |
       |                 |            |     LEF                                                      |
             |                               |
  2056 | Client          | ClientRead | lock actor;                                                  | 2024-09-08 19:41:50.923561+09 | 2024-09-08 19:42:03.600176+09 | 00:00:57.112649
  3244 | Lock            | relation   | SELECT * from actor;                                         | 2024-09-08 19:42:15.933675+09 | 2024-09-08 19:42:23.136253+09 | 00:00:37.576572
 16400 | Client          | ClientRead | SELECT DISTINCT att.attname as name, att.attnum as OID, pg_c | 2024-09-08 19:27:38.693773+09 | 2024-09-08 19:27:40.32982+09  | 00:15:20.383005
(4 行)

以上で、現時点におけるクエリの確認は終了です。