Monitor AlloyDB Omni database performance

Select a documentation version:

This page describes how to monitor your AlloyDB Omni database performance using PostgreSQL observability scripts.

View state of connected processes and wait events

You can determine any processes connected to your AlloyDB Omni instance as well as any backends that are waiting for activity by querying the pg_stat_activity view.

  SELECT 
  
 pid 
 , 
  
 datname 
 , 
  
 age 
 ( 
 backend_xid 
 ) 
  
 AS 
  
 age_in_xids 
 , 
  
 now 
 () 
  
 - 
  
 xact_start 
  
 AS 
  
 xact_age 
 , 
  
 now 
 () 
  
 - 
  
 query_start 
  
 AS 
  
 query_age 
 , 
  
 state 
 , 
  
 wait_event_type 
 , 
  
 wait_event 
 , 
  
 query_id 
 , 
  
 query 
 FROM 
  
 pg_stat_activity 
 WHERE 
  
 state 
  
 != 
  
 'idle' 
  
 AND 
  
 pid 
 <> 
 pg_backend_pid 
 () 
 ORDER 
  
 BY 
  
 4 
  
 DESC 
 LIMIT 
  
 10 
 ; 
 

View largest tables

You can determine the size of your largest tables by querying the pg_stat_user_tables view.

  SELECT 
  
 oid 
 , 
  
 oid 
 :: 
 regclass 
  
 table_name 
 , 
  
 pg_size_pretty 
 ( 
 pg_relation_size 
 ( 
 oid 
 )), 
  
 relpages 
 , 
  
 s 
 . 
 seq_scan 
 , 
  
 s 
 . 
 idx_scan 
 FROM 
  
 pg_class 
 , 
  
 pg_stat_user_tables 
  
 s 
 WHERE 
  
 s 
 . 
 relid 
  
 = 
  
 oid 
  
 AND 
  
 oid 
 > 
 16383 
  
 AND 
  
 relpages 
 > 
 100 
  
 AND 
  
 relkind 
  
 = 
  
 'r' 
 ORDER 
  
 BY 
  
 relpages 
  
 DESC 
 LIMIT 
  
 20 
 ; 
 

View top sequential scans

You can view the top sequential scans by querying the pg_stat_user_tables view.

  SELECT 
  
 relid 
 , 
  
 relname 
 , 
  
 seq_scan 
 , 
  
 pg_size_pretty 
 ( 
 pg_relation_size 
 ( 
 relid 
 )) 
 FROM 
  
 pg_stat_user_tables 
 ORDER 
  
 BY 
  
 seq_scan 
  
 DESC 
 LIMIT 
  
 15 
 ; 
 

View top index scans

You can view the top index scans by querying the pg_stat_user_tables view.

  SELECT 
  
 relid 
 , 
  
 relid 
 :: 
 regclass 
  
 table_name 
 , 
  
 idx_scan 
 , 
  
 pg_size_pretty 
 ( 
 pg_relation_size 
 ( 
 relid 
 )) 
 FROM 
  
 pg_stat_user_tables 
 WHERE 
  
 idx_scan 
 > 
 10 
 ORDER 
  
 BY 
  
 idx_scan 
  
 DESC 
 LIMIT 
  
 15 
 ; 
 

View longest running transactions

You can view the longest running transactions by querying the pg_stat_activity view and checking the age of the transaction.

  SELECT 
  
 pid 
 , 
  
 age 
 ( 
 backend_xid 
 ) 
  
 AS 
  
 age_in_xids 
 , 
  
 now 
 () 
  
 - 
  
 xact_start 
  
 AS 
  
 xact_age 
 , 
  
 now 
 () 
  
 - 
  
 query_start 
  
 AS 
  
 query_age 
 , 
  
 state 
 , 
  
 query 
 FROM 
  
 pg_stat_activity 
 WHERE 
  
 state 
  
 != 
  
 'idle' 
 ORDER 
  
 BY 
  
 2 
  
 DESC 
 LIMIT 
  
 10 
 ; 
 

Check vacuum progress

You can check the progress of vacuum operations by querying the pg_stat_progress_vacuum view and joining it with the pg_stat_activity view using process IDs.

  SELECT 
  
 p 
 . 
 pid 
 , 
  
 now 
 () 
  
 - 
  
 a 
 . 
 xact_start 
  
 AS 
  
 duration 
 , 
  
 coalesce 
 ( 
 wait_event_type 
  
 || 
 '.' 
 || 
  
 wait_event 
 , 
  
 'f' 
 ) 
  
 AS 
  
 waiting 
 , 
  
 CASE 
  
 WHEN 
  
 a 
 . 
 query 
  
 ~* 
 '^autovacuum.*to prevent wraparound' 
  
 THEN 
  
 'wraparound' 
  
 WHEN 
  
 a 
 . 
 query 
  
 ~* 
 '^vacuum' 
  
 THEN 
  
 'user' 
  
 ELSE 
  
 'regular' 
  
 END 
  
 AS 
  
 mode 
 , 
  
 p 
 . 
 datname 
  
 AS 
  
 database 
 , 
  
 p 
 . 
 relid 
 :: 
 regclass 
  
 AS 
  
 table 
 , 
  
 p 
 . 
 phase 
 , 
  
 pg_size_pretty 
 ( 
 p 
 . 
 heap_blks_total 
  
 * 
  
 current_setting 
 ( 
 'block_size' 
 ):: 
 int 
 ) 
  
 AS 
  
 table_size 
 , 
  
 pg_size_pretty 
 ( 
 pg_total_relation_size 
 ( 
 relid 
 )) 
  
 AS 
  
 total_size 
 , 
  
 pg_size_pretty 
 ( 
 p 
 . 
 heap_blks_scanned 
  
 * 
  
 current_setting 
 ( 
 'block_size' 
 ):: 
 int 
 ) 
  
 AS 
  
 scanned 
 , 
  
 pg_size_pretty 
 ( 
 p 
 . 
 heap_blks_vacuumed 
  
 * 
  
 current_setting 
 ( 
 'block_size' 
 ):: 
 int 
 ) 
  
 AS 
  
 vacuumed 
 , 
  
 round 
 ( 
 100 
 . 
 0 
  
 * 
  
 p 
 . 
 heap_blks_scanned 
  
 / 
  
 p 
 . 
 heap_blks_total 
 , 
  
 1 
 ) 
  
 AS 
  
 scanned_pct 
 , 
  
 round 
 ( 
 100 
 . 
 0 
  
 * 
  
 p 
 . 
 heap_blks_vacuumed 
  
 / 
  
 p 
 . 
 heap_blks_total 
 , 
  
 1 
 ) 
  
 AS 
  
 vacuumed_pct 
 , 
  
 p 
 . 
 index_vacuum_count 
 , 
  
 round 
 ( 
 100 
 . 
 0 
  
 * 
  
 p 
 . 
 num_dead_tuples 
  
 / 
  
 p 
 . 
 max_dead_tuples 
 , 
 1 
 ) 
  
 AS 
  
 dead_pct 
 FROM 
  
 pg_stat_progress_vacuum 
  
 p 
 JOIN 
  
 pg_stat_activity 
  
 a 
  
 using 
  
 ( 
 pid 
 ) 
 ORDER 
  
 BY 
  
 now 
 () 
  
 - 
  
 a 
 . 
 xact_start 
  
 DESC 
 ; 
 

View asynchronous queries

To view queries that are running asynchronously, you can query the pg_stat_activity view and filter for queries that are not the leader process.

  SELECT 
  
 query 
 , 
  
 leader_pid 
 , 
  
 array_agg 
 ( 
 pid 
 ) 
  
 FILTER 
  
 ( 
 WHERE 
  
 leader_pid 
  
 != 
  
 pid 
 ) 
  
 AS 
  
 members 
 FROM 
  
 pg_stat_activity 
 WHERE 
  
 leader_pid 
  
 IS 
  
 NOT 
  
 NULL 
 GROUP 
  
 BY 
  
 query 
 , 
  
 leader_pid 
 ; 
 

View blocking lock SQL

You can view activity that is blocked by querying the pg_locks view and joining it with the pg_stat_activity view.

  SELECT 
  
 blocked_locks 
 . 
 pid 
  
 AS 
  
 blocked_pid 
 , 
  
 blocked_activity 
 . 
 usename 
  
 AS 
  
 blocked_user 
 , 
  
 blocking_locks 
 . 
 pid 
  
 AS 
  
 blocking_pid 
 , 
  
 blocking_activity 
 . 
 usename 
  
 AS 
  
 blocking_user 
 , 
  
 blocked_activity 
 . 
 query 
  
 AS 
  
 blocked_statement 
 , 
  
 blocked_activity 
 . 
 wait_event 
  
 AS 
  
 blocked_wait_event 
 , 
  
 blocking_activity 
 . 
 wait_event 
  
 AS 
  
 blocking_wait_event 
 , 
  
 blocking_activity 
 . 
 query 
  
 AS 
  
 current_statement_in_blocking_process 
  
 FROM 
  
 pg_catalog 
 . 
 pg_locks 
  
 blocked_locks 
  
 JOIN 
  
 pg_catalog 
 . 
 pg_stat_activity 
  
 blocked_activity 
  
 ON 
  
 blocked_activity 
 . 
 pid 
  
 = 
  
 blocked_locks 
 . 
 pid 
  
 JOIN 
  
 pg_catalog 
 . 
 pg_locks 
  
 blocking_locks 
  
 ON 
  
 blocking_locks 
 . 
 locktype 
  
 = 
  
 blocked_locks 
 . 
 locktype 
  
 AND 
  
 blocking_locks 
 . 
 database 
  
 IS 
  
 NOT 
  
 DISTINCT 
  
 FROM 
  
 blocked_locks 
 . 
 database 
  
 AND 
  
 blocking_locks 
 . 
 relation 
  
 IS 
  
 NOT 
  
 DISTINCT 
  
 FROM 
  
 blocked_locks 
 . 
 relation 
  
 AND 
  
 blocking_locks 
 . 
 page 
  
 IS 
  
 NOT 
  
 DISTINCT 
  
 FROM 
  
 blocked_locks 
 . 
 page 
  
 AND 
  
 blocking_locks 
 . 
 tuple 
  
 IS 
  
 NOT 
  
 DISTINCT 
  
 FROM 
  
 blocked_locks 
 . 
 tuple 
  
 AND 
  
 blocking_locks 
 . 
 virtualxid 
  
 IS 
  
 NOT 
  
 DISTINCT 
  
 FROM 
  
 blocked_locks 
 . 
 virtualxid 
  
 AND 
  
 blocking_locks 
 . 
 transactionid 
  
 IS 
  
 NOT 
  
 DISTINCT 
  
 FROM 
  
 blocked_locks 
 . 
 transactionid 
  
 AND 
  
 blocking_locks 
 . 
 classid 
  
 IS 
  
 NOT 
  
 DISTINCT 
  
 FROM 
  
 blocked_locks 
 . 
 classid 
  
 AND 
  
 blocking_locks 
 . 
 objid 
  
 IS 
  
 NOT 
  
 DISTINCT 
  
 FROM 
  
 blocked_locks 
 . 
 objid 
  
 AND 
  
 blocking_locks 
 . 
 objsubid 
  
 IS 
  
 NOT 
  
 DISTINCT 
  
 FROM 
  
 blocked_locks 
 . 
 objsubid 
  
 AND 
  
 blocking_locks 
 . 
 pid 
  
 != 
  
 blocked_locks 
 . 
 pid 
  
 JOIN 
  
 pg_catalog 
 . 
 pg_stat_activity 
  
 blocking_activity 
  
 ON 
  
 blocking_activity 
 . 
 pid 
  
 = 
  
 blocking_locks 
 . 
 pid 
  
 WHERE 
  
 NOT 
  
 blocked_locks 
 . 
 granted 
 ; 
 

Determine work_mem and temp_buffers size effectiveness

To determine if your work_mem and temp_buffers are sized correctly for your needs, you can query pg_stat_database view and check the postgres.log file. Using pg_stat_database , execute the following query and if there is any growth in temp_files or temp_bytes between executions, then tuning is likely necessary for either work_mem or temp_buffers .

  SELECT 
  
 datname 
 , 
  
 temp_files 
 , 
  
 temp_bytes 
 FROM 
  
 pg_stat_database 
 ; 
 

After running this, check the postgres.log file to see if temporary files were used:

LOG: [fd.c:1772] temporary file: path "base/pgsql_tmp/pgsql_tmp4640.1", size 139264

The goal is to minimize the creation of temporary files, not completely prevent them from happening. This is because setting both work_mem and temp_buffers is a balance between available memory on the host and the number of connections that require the memory. Setting these parameters correctly requires understanding about each individual workload.

Design a Mobile Site
View Site in Mobile | Classic
Share by: