瀚高数据库常用系统表查询入门指南(附常用SQL)

文章目录

环境

系统平台:Linux x86-64 Red Hat Enterprise Linux 7

版本:9.0.5

文档用途

本文以瀚高数据库V9为例,介绍数据库中常用的系统表,并列出常用的系统表查询SQL。

详细信息

1. 常用系统表/视图汇总

数据库核心系统表/视图都以 pg_ 为前缀,存储在 pg_catalog 下,是数据库管理自身元数据的基础;这些系统表/视图,按照功能可以分为:对象元数据、类型与转换、索引与访问方法、约束与默认值、权限与安全、依赖与注释、扩展与语言、复制与发布、外部数据、统计信息、系统视图等。

常用系统表/视图汇总如下:

系统表/视图 解释 作用
pg_authid 认证标识(角色/用户) 存储所有数据库角色(包括用户和组)的认证信息
pg_cast 类型转换 存储数据类型之间的转换规则
pg_class 所有关系对象 核心系统表,存储对象:表、索引、视图、序列、TOAST 表等
pg_constraint 约束 存储表上的所有约束:主键、外键、唯一约束、检查约束、排除约束
pg_database 数据库 存储所有 database 信息
pg_db_role_setting 数据库/角色级别设置 存储通过 ALTER DATABASE ... SET 或 ALTER ROLE ... SET 设置的配置参数
pg_depend 依赖关系 记录数据库内对象之间的依赖关系,维护对象间的依赖链,确保删除操作不会破坏引用完整性。例如:表的列依赖数据类型,索引依赖表,视图依赖底层表
pg_description 注释 存储数据库内对象的注释(通过 COMMENT ON 命令设置)
pg_extension 扩展 存储已在 database 中创建的扩展信息
pg_foreign_data_wrapper 外部数据包装器 存储外部数据包装器(FDW)的定义,描述如何连接到外部数据源。每个包装器对应一种外部数据访问方法(如 postgres_fdw、file_fdw)
pg_foreign_server 外部服务器 定义连接到外部数据源的服务器信息,CREATE SERVER 定义的远程服务器。包含连接类型、版本、选项等
pg_foreign_table 外部表 定义外部表的元数据
pg_index 索引 存储关于索引的详细元数据
pg_namespace 命名空间(Schema) 存储所有 schema
pg_operator 操作符 存储所有的操作符
pg_proc 函数和存储过程 存储所有函数、存储过程、聚合函数、窗口函数的定义,包含参数、返回类型、源代码、成本估算等全部信息
pg_sequence 序列 存储序列的定义
pg_tablespace 表空间 存储所有表空间的定义
pg_trigger 触发器 存储所有触发器的定义
pg_user_mapping 用户映射 定义外部服务器的用户映射(FDW 用户名/密码映射)
pg_available_extensions 可用扩展列表 列出系统可用的所有扩展,以及当前数据库中已安装的版本号(未安装则为 NULL)
pg_available_extension_versions 扩展版本详情 列出系统可用的所有扩展及其可安装的各个版本信息
pg_indexes 索引列表 展示所有索引的详细信息(名称、schema、表、定义语句)
pg_locks 锁信息 显示当前持有的和等待的锁
pg_replication_slots 复制槽 显示所有复制槽信息
pg_roles 角色信息 显示所有角色的信息
pg_stat_activity 活动会话 显示当前所有后端进程(客户端连接与后台进程)的状态:pid、用户、数据库、查询、状态、等待事件、事务/查询开始时间等,是排查性能与锁问题最常用的视图
pg_settings 运行时配置参数 显示当前实例(会话视角)的所有运行时配置参数及其当前值、单位、默认值等
pg_tables 表列表 列出所有表和分区表的信息
pg_views 视图列表 列出所有视图的定义

2. 常用查询 SQL

2.1 用户表

pg_class 关联 pg_namespace,列出当前 database 中的用户自定义对象:表、分区表、视图、物化视图、外部表等,可用于快速盘点业务库对象清单;注意 Size 列基于 pg_table_size 计算,需要整体大小时使用 pg_total_relation_size。

sql 复制代码
SELECT n.nspname as "Schema",
  c.relname as "Name",
  CASE c.relkind 
    WHEN 'r' THEN 'table' 
    WHEN 'v' THEN 'view' 
    WHEN 'm' THEN 'materialized view' 
    WHEN 'i' THEN 'index' 
    WHEN 'S' THEN 'sequence' 
    WHEN 's' THEN 'special' 
    WHEN 't' THEN 'TOAST table' 
    WHEN 'f' THEN 'foreign table' 
    WHEN 'p' THEN 'partitioned table' 
    WHEN 'I' THEN 'partitioned index' END as "Type",
  pg_catalog.pg_get_userbyid(c.relowner) as "Owner",
  CASE c.relpersistence 
    WHEN 'g' THEN 'session' 
    WHEN 'p' THEN 'permanent' 
    WHEN 't' THEN 'temporary' 
    WHEN 'u' THEN 'unlogged' END as "Persistence",
  am.amname as "Access method",
  pg_catalog.pg_size_pretty(pg_catalog.pg_table_size(c.oid)) as "Size",
  pg_catalog.obj_description(c.oid, 'pg_class') as "Description"
FROM pg_catalog.pg_class c
     LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace
     LEFT JOIN pg_catalog.pg_am am ON am.oid = c.relam
WHERE c.relkind IN ('r','p','v','m','f')
      AND n.nspname <> 'pg_catalog'
      AND n.nspname <> 'information_schema'
	  AND n.nspname <> 'sys'
ORDER BY 1,2;

2.2 用户索引

列出用户索引的名称、所属表与 Schema、索引大小、完整定义(pg_get_indexdef),并关联 pg_stat_user_indexes 展示累计扫描次数与读取行数,用于索引膨胀排查等,以及识别从未被使用的索引------idx_scan 为 0 的索引可考虑删除。

sql 复制代码
SELECT
    n.nspname AS schema_name,
    t.relname AS table_name,
    i.relname AS index_name,
    ix.indisunique AS is_unique,
    ix.indisprimary AS is_primary,
    ix.indisvalid AS is_valid,
    pg_size_pretty(pg_relation_size(i.oid)) AS index_size,
    pg_get_indexdef(i.oid) AS index_definition,
    s.idx_scan AS scan_count,
    s.idx_tup_read AS tuples_read,
    s.idx_tup_fetch AS tuples_fetched
FROM pg_class i
JOIN pg_index ix ON i.oid = ix.indexrelid
JOIN pg_class t ON ix.indrelid = t.oid
JOIN pg_namespace n ON i.relnamespace = n.oid
LEFT JOIN pg_stat_user_indexes s ON s.indexrelid = i.oid
WHERE n.nspname NOT IN ('pg_catalog', 'information_schema')
  AND i.relkind = 'i'
  AND n.nspname !~ '^pg_toast'
ORDER BY n.nspname, t.relname, i.relname;

2.3 用户视图

展示用户视图的属主、注释与视图定义(pg_get_viewdef)。

sql 复制代码
SELECT
    n.nspname AS schema_name,
    c.relname AS view_name,
    pg_get_userbyid(c.relowner) AS owner,
    CASE WHEN c.reltuples < 0 THEN NULL ELSE c.reltuples::bigint END AS estimated_rows,
    obj_description(c.oid, 'pg_class') AS comment,
    pg_get_viewdef(c.oid, true) AS view_definition
FROM pg_class c
JOIN pg_namespace n ON c.relnamespace = n.oid
WHERE n.nspname NOT IN ('pg_catalog', 'information_schema')
  AND c.relkind = 'v'
ORDER BY n.nspname, c.relname;

2.4 用户物化视图

列出物化视图的总大小、是否已填充(relispopulated)、估算行数与定义;relispopulated 为 false 表示物化视图已创建但尚未 REFRESH,此时查询会报错。

sql 复制代码
SELECT
    n.nspname AS schema_name,
    c.relname AS matview_name,
    pg_get_userbyid(c.relowner) AS owner,
    pg_size_pretty(pg_total_relation_size(c.oid)) AS total_size,
    c.relispopulated AS is_populated,
    c.reltuples::bigint AS estimated_rows,
    pg_get_viewdef(c.oid, true) AS view_definition
FROM pg_class c
JOIN pg_namespace n ON c.relnamespace = n.oid
WHERE n.nspname NOT IN ('pg_catalog', 'information_schema')
  AND c.relkind = 'm'
ORDER BY n.nspname, c.relname;

2.5 用户序列

列出所有用户序列的增量、起始/最小/最大值、缓存、是否循环、当前值,以及被哪张表的哪一列拥有(owned_by),用于梳理自增主键配置。查询序列当前值,防止溢出。

sql 复制代码
SELECT
    n.nspname AS schema_name,
    c.relname AS sequence_name,
    pg_get_userbyid(c.relowner) AS owner,
    s.seqincrement AS increment,
    s.seqstart AS start_value,
    s.seqmin AS min_value,
    s.seqmax AS max_value,
    s.seqcache AS cache_size,
    s.seqcycle AS cycle,
    pg_sequence_last_value(c.oid) AS last_value,
    (SELECT a.attrelid::regclass::text || '.' || a.attname
     FROM pg_depend d JOIN pg_attribute a ON d.refobjid = a.attrelid AND d.refobjsubid = a.attnum
     WHERE d.objid = c.oid AND d.deptype = 'a' LIMIT 1) AS owned_by
FROM pg_class c
JOIN pg_namespace n ON c.relnamespace = n.oid
JOIN pg_sequence s ON c.oid = s.seqrelid
WHERE n.nspname NOT IN ('pg_catalog', 'information_schema')
  AND c.relkind = 'S'
ORDER BY n.nspname, c.relname;

-- 序列当前值,防止溢出
SELECT 
    n.nspname || '.' || c.relname AS qualified_name,
    pg_sequence_last_value(c.oid) AS current_value,
    s.seqmax AS max_value,
    (s.seqmax - COALESCE(pg_sequence_last_value(c.oid), s.seqmin)) AS remaining 
FROM pg_class c
JOIN pg_namespace n ON c.relnamespace = n.oid
JOIN pg_sequence s ON c.oid = s.seqrelid
WHERE c.relkind = 'S' 
ORDER BY (s.seqmax - COALESCE(pg_sequence_last_value(c.oid), s.seqmin)) ASC
LIMIT 50;

2.6 用户函数/存储过程

列出用户自定义函数与存储过程的对象类型(函数/存储过程/窗口/聚合)、参数、返回类型、语言、易变性(volatile/stable/immutable)、是否严格(strict)、注释与源码等。

sql 复制代码
SELECT n.nspname AS schema_name, p.proname AS function_name,
    pg_get_function_arguments(p.oid) AS arguments, pg_get_function_result(p.oid) AS return_type,
    CASE p.prokind 
      WHEN 'f' THEN '函数' 
      WHEN 'p' THEN '存储过程' 
      WHEN 'w' THEN '窗口函数' 
      WHEN 'a' THEN '聚合函数'
    END AS object_type,
    l.lanname AS language,
    CASE p.provolatile 
      WHEN 'v' THEN 'volatile(可变的)' 
      WHEN 's' THEN 'stable(稳定的)' 
      WHEN 'i' THEN 'immutable(不可变的)'
    END AS volatility,
    p.proisstrict AS is_strict,
    p.prosecdef AS security_definer,
    p.procost AS estimated_cost,
    p.prorows AS estimated_rows,
    obj_description(p.oid, 'pg_proc') AS comment,
    p.prosrc AS source_code
FROM pg_proc p
JOIN pg_namespace n ON p.pronamespace = n.oid
JOIN pg_language l ON p.prolang = l.oid
WHERE n.nspname NOT IN ('pg_catalog', 'information_schema')
  AND p.prokind IN ('f', 'p', 'w','a')
ORDER BY n.nspname, p.proname;

2.7 约束

输出约束的类型(主键/唯一/外键/检查等)与详细定义,包括外键的引用表与引用列。

sql 复制代码
SELECT n.nspname AS schema_name, c.relname AS table_name, con.conname AS constraint_name,
    CASE con.contype
        WHEN 'p' THEN 'PRIMARY KEY'
        WHEN 'u' THEN 'UNIQUE'
        WHEN 'f' THEN 'FOREIGN KEY'
        WHEN 'c' THEN 'CHECK'
        WHEN 'x' THEN 'EXCLUDE'
    END AS constraint_type,
    -- 详情:主键/唯一/外键的具体列
    CASE con.contype
        WHEN 'p' THEN
            'PRIMARY KEY (' ||
            (SELECT string_agg(a.attname, ', ' ORDER BY a.attnum)
             FROM pg_attribute a WHERE a.attrelid = con.conrelid AND a.attnum = ANY(con.conkey)) || ')'
        WHEN 'u' THEN
            'UNIQUE (' ||
            (SELECT string_agg(a.attname, ', ' ORDER BY a.attnum)
             FROM pg_attribute a WHERE a.attrelid = con.conrelid AND a.attnum = ANY(con.conkey)) || ')'
        WHEN 'f' THEN
            'FOREIGN KEY (' ||
            (SELECT string_agg(a.attname, ', ' ORDER BY a.attnum)
             FROM pg_attribute a WHERE a.attrelid = con.conrelid AND a.attnum = ANY(con.conkey)) ||
            ') REFERENCES ' || con.confrelid::regclass::text ||
            ' (' ||
            (SELECT string_agg(a.attname, ', ' ORDER BY a.attnum)
             FROM pg_attribute a WHERE a.attrelid = con.confrelid AND a.attnum = ANY(con.confkey)) || ')'
        WHEN 'c' THEN pg_get_constraintdef(con.oid)
        WHEN 'x' THEN pg_get_constraintdef(con.oid)
        ELSE pg_get_constraintdef(con.oid)
    END AS constraint_detail,
    CASE con.contype WHEN 'f' THEN con.confrelid::regclass::text ELSE NULL END AS references_table,
    CASE
        WHEN con.contype = 'p' THEN '主键'
        WHEN con.contype = 'u' THEN '唯一'
        WHEN con.contype = 'f' THEN '外键'
        WHEN con.contype = 'c' THEN '检查'
        WHEN con.contype = 'x' THEN '排除'
    END AS icon,
    con.condeferrable AS deferrable, con.condeferred AS deferred, con.convalidated AS validated,
    (SELECT string_agg(a.attname, ', ' ORDER BY a.attnum)
     FROM pg_attribute a WHERE a.attrelid = con.conrelid AND a.attnum = ANY(con.conkey)) AS constraint_columns
FROM pg_constraint con
JOIN pg_class c ON con.conrelid = c.oid
JOIN pg_namespace n ON c.relnamespace = n.oid
WHERE n.nspname NOT IN ('pg_catalog', 'information_schema')
ORDER BY con.contype, n.nspname, c.relname, con.conname;

2.8 触发器

展示触发器的启用状态(O:触发器在"origin"和"local"模式触发,D:触发器被禁用,R:触发器在"replica"模式触发,A:触发器总是触发)、触发级别(行级/语句级)、触发时机(BEFORE/AFTER/INSTEAD OF)、触发事件(INSERT/UPDATE/DELETE/TRUNCATE)与完整定义,用于触发器审计与性能评估(行级触发器对 DML 性能影响明显)、排查被禁用的触发器。

sql 复制代码
SELECT n.nspname AS schema_name, c.relname AS table_name, t.tgname AS trigger_name,
    CASE WHEN t.tgenabled = 'O' THEN '启用'
         WHEN t.tgenabled = 'D' THEN '禁用'
         WHEN t.tgenabled = 'R' THEN 'Replica'
         WHEN t.tgenabled = 'A' THEN 'Always'
    END AS enabled_state,
    CASE WHEN t.tgtype & 1 = 1 THEN 'ROW' ELSE 'STATEMENT' END AS trigger_level,
    CASE WHEN t.tgtype & 2 = 2 THEN 'BEFORE' WHEN t.tgtype & 64 = 64 THEN 'INSTEAD OF' ELSE 'AFTER' 
    END AS trigger_timing,
    (SELECT string_agg(e.event, ', ' ORDER BY e.ord)
     FROM (SELECT 'INSERT' AS event, 1 AS ord WHERE t.tgtype & 4 = 4
           UNION ALL SELECT 'DELETE', 2 WHERE t.tgtype & 8 = 8
           UNION ALL SELECT 'UPDATE', 3 WHERE t.tgtype & 16 = 16
           UNION ALL SELECT 'TRUNCATE', 4 WHERE t.tgtype & 32 = 32
     ) e
    ) AS trigger_events,
    pg_get_triggerdef(t.oid) AS trigger_definition,
    p.proname AS function_name,
    obj_description(t.oid, 'pg_trigger') AS comment
FROM pg_trigger t
JOIN pg_class c ON t.tgrelid = c.oid
JOIN pg_namespace n ON c.relnamespace = n.oid
JOIN pg_proc p ON t.tgfoid = p.oid
WHERE n.nspname NOT IN ('pg_catalog', 'information_schema')
  AND t.tgisinternal = false
GROUP BY n.nspname, c.relname, t.tgname, t.tgenabled, t.tgtype, t.oid, p.proname
ORDER BY n.nspname, c.relname, t.tgname;

2.9 角色与用户 (Roles / Users)

列出用户角色的超级用户、建库、建角色、登录、复制、连接数限制、密码过期时间等属性。

sql 复制代码
SELECT
    r.rolname AS role_name,
    r.rolsuper AS is_superuser,
    r.rolcreatedb AS can_create_db,
    r.rolcreaterole AS can_create_role,
    r.rolcanlogin AS can_login,
    r.rolreplication AS is_replication,
    r.rolconnlimit AS connection_limit,
    r.rolvaliduntil AS password_expiry,
    r.rolbypassrls AS bypass_row_level_security,
    (SELECT string_agg(r2.rolname, ', ') 
     FROM pg_auth_members m 
     JOIN pg_authid r2 ON m.roleid = r2.oid
     WHERE m.member = r.oid) AS member_of,
    (SELECT string_agg(r2.rolname, ', ')
     FROM pg_auth_members m
     JOIN pg_authid r2 ON m.member = r2.oid
     WHERE m.roleid = r.oid) AS members
FROM pg_authid r
WHERE r.rolname NOT LIKE 'pg_%'
ORDER BY r.rolsuper DESC, r.rolname;

2.10 FDW 定义

列出外部数据包装器的属主、handler、validator 与选项,用于确认 FDW 类型(postgres_fdw、file_fdw 等)及其权限归属。

sql 复制代码
SELECT fdw.fdwname, fdw.fdwowner::regrole, fdw.fdwhandler::regproc, fdw.fdwvalidator::regproc, fdw.fdwoptions, 
    obj_description(fdw.oid, 'pg_foreign_data_wrapper') AS comment
FROM pg_foreign_data_wrapper fdw
ORDER BY fdw.fdwname;

2.11 Foreign Server 定义

展示外部服务器的属主、所属包装器、类型、版本与连接选项,用于梳理实例对外部数据源的连接定义。

sql 复制代码
SELECT s.srvname, s.srvowner::regrole, w.fdwname, s.srvtype, s.srvversion, s.srvoptions, 
    obj_description(s.oid, 'pg_foreign_server') AS comment
FROM pg_foreign_server s
JOIN pg_foreign_data_wrapper w ON s.srvfdw = w.oid
ORDER BY s.srvname;

2.12 用户映射 User Mappings

列出外部服务器上的本地用户映射及映射选项。

sql 复制代码
SELECT s.srvname AS server_name, 
    CASE WHEN um.umuser = 0 THEN 'PUBLIC' ELSE um.umuser::regrole::text END AS local_user,
    um.umoptions AS options
FROM pg_user_mapping um
JOIN pg_foreign_server s ON um.umserver = s.oid
ORDER BY s.srvname, local_user;

2.13 外部表 (Foreign Tables)

列出外部表的所属 Schema、关联服务器、选项与属主。

sql 复制代码
SELECT n.nspname, c.relname, s.srvname AS server_name, ft.ftoptions AS options, pg_get_userbyid(c.relowner) AS owner 
FROM pg_foreign_table ft
JOIN pg_class c ON ft.ftrelid = c.oid
JOIN pg_namespace n ON c.relnamespace = n.oid
JOIN pg_foreign_server s ON ft.ftserver = s.oid
WHERE n.nspname NOT IN ('pg_catalog', 'information_schema')
ORDER BY n.nspname, c.relname;

2.14 extension

列出当前数据库已创建的扩展(版本、所属 Schema、是否可重定位)。

列出系统已安装但尚未创建的扩展。

已创建扩展

sql 复制代码
SELECT e.extname, e.extversion, n.nspname, 
    CASE WHEN e.extrelocatable THEN 'YES' ELSE 'NO' END AS relocatable,
    obj_description(e.oid, 'pg_extension') AS description
FROM pg_extension e
JOIN pg_namespace n ON e.extnamespace = n.oid
ORDER BY e.extname;

已安装但尚未创建的扩展

sql 复制代码
SELECT name, default_version, comment
FROM pg_available_extensions
WHERE installed_version IS NULL
ORDER BY name;

2.15 表空间

列出表空间的路径、大小、选项、使用该表空间的 database 与注释。

sql 复制代码
SELECT
    spcname AS tablespace_name,
    pg_tablespace_location(oid) AS location,
    pg_size_pretty(pg_tablespace_size(spcname)) AS size,
    spcoptions AS options,
    (SELECT string_agg(datname, ', ') FROM pg_database
     WHERE dattablespace = pg_tablespace.oid) AS used_by_databases,
    obj_description(oid, 'pg_tablespace') AS comment
FROM pg_tablespace
ORDER BY spcname;

2.16 类型转换 (cast)

展示类型转换规则:源类型、目标类型、转换方式(binary coercible / inout / 函数)与是否隐式(Implicit)。用于排查隐式转换导致索引失效的问题(表达式上的隐式 CAST 通常无法走索引),以及评估自定义 CAST 的影响范围。

sql 复制代码
SELECT pg_catalog.format_type(castsource, NULL) AS "Source type",
       pg_catalog.format_type(casttarget, NULL) AS "Target type",
       CASE WHEN c.castmethod = 'b' THEN '(binary coercible)' 
            WHEN c.castmethod = 'i' THEN '(with inout)'
            ELSE p.proname
       END AS "Function",
       CASE WHEN c.castcontext = 'e' THEN 'no' WHEN c.castcontext = 'a' THEN 'in assignment' ELSE 'yes' END AS "Implicit?"
FROM pg_catalog.pg_cast c LEFT JOIN pg_catalog.pg_proc p ON c.castfunc = p.oid
ORDER BY 1, 2;

2.17 操作符

列出操作符的名称、左右参数类型、返回类型与注释,用于梳理自定义操作符、排查查询计划中的操作符解析异常,以及通过 oprcode 确认操作符对应的实现函数。

sql 复制代码
SELECT n.nspname as "Schema",
  o.oprname AS "Name",
  CASE WHEN o.oprkind='l' THEN NULL ELSE pg_catalog.format_type(o.oprleft, NULL) END AS "Left arg type",
  CASE WHEN o.oprkind='r' THEN NULL ELSE pg_catalog.format_type(o.oprright, NULL) END AS "Right arg type",
  pg_catalog.format_type(o.oprresult, NULL) AS "Result type",
  coalesce(pg_catalog.obj_description(o.oid, 'pg_operator'),
           pg_catalog.obj_description(o.oprcode, 'pg_proc')) AS "Description"
FROM pg_catalog.pg_operator o
     LEFT JOIN pg_catalog.pg_namespace n ON n.oid = o.oprnamespace
ORDER BY 1, 2, 3, 4;

2.18 查看实例中 database 信息

展示database的属主、编码、排序规则(Collate/Ctype)、访问权限、大小与所在表空间。

sql 复制代码
SELECT d.datname as "Name",
       pg_catalog.pg_get_userbyid(d.datdba) as "Owner",
       pg_catalog.pg_encoding_to_char(d.encoding) as "Encoding",
       d.datcollate as "Collate", d.datctype as "Ctype", 
       pg_catalog.array_to_string(d.datacl, E'\n') AS "Access privileges",
       CASE WHEN pg_catalog.has_database_privilege(d.datname, 'CONNECT')
            THEN pg_catalog.pg_size_pretty(pg_catalog.pg_database_size(d.datname))
            ELSE 'No Access'
       END as "Size",
       t.spcname as "Tablespace"
FROM pg_catalog.pg_database d
  JOIN pg_catalog.pg_tablespace t on d.dattablespace = t.oid
ORDER BY 1;

2.19 数据库连接数

sql 复制代码
select '最大连接数:' as name, setting from pg_settings where name = 'max_connections'
union all
select '当前总连接数:', count(1)::varchar from pg_stat_activity
union all
select '当前活跃连接数(非idle):', count(1)::varchar from pg_stat_activity where state <> 'idle'
union all
select '当前空闲连接数(idle):', count(1)::varchar from pg_stat_activity where state = 'idle'
union all
select '查询开始超过10分钟的会话数:', count(1)::varchar 
  from pg_stat_activity 
  where query_start < (now() - interval '10 min') ;

用于监控数据库连接情况,通过 pg_stat_activity 统计总连接数、活动会话数和执行超过 10 分钟的会话,帮助评估数据库的负载和连接使用情况;可辅助连接数监控和容量规划,判断是否接近 max_connections 上限,排查连接泄漏问题,分析连接波动趋势。

2.20 查看数据库运行时间

sql 复制代码
--查询数据库启动时间
select pg_postmaster_start_time();

--查询数据库运行总时间
SELECT age(now(), pg_postmaster_start_time()) AS uptime;

pg_postmaster_start_time() 返回数据库实例的启动时间,age(now(), start_time) 计算实例从启动到当前的总运行时长,以 interval 类型返回。

2.21 查询当前 database 所有表大小

sql 复制代码
--当前 database 下表大小,按大小排序
SELECT n.nspname as "Schema", c.relname as "Name",
  CASE c.relkind WHEN 'r' THEN 'table' 
    WHEN 'v' THEN 'view' 
    WHEN 'm' THEN 'materialized view' 
    WHEN 'i' THEN 'index' 
    WHEN 'S' THEN 'sequence' 
    WHEN 's' THEN 'special' 
    WHEN 'f' THEN 'foreign table' 
    WHEN 'p' THEN 'partitioned table' 
    WHEN 'I' THEN 'partitioned index' END as "Type",
  pg_catalog.pg_get_userbyid(c.relowner) as "Owner",
  pg_size_pretty(pg_total_relation_size(c.oid)) AS total_size,
  pg_size_pretty(pg_table_size(c.oid)) AS table_size,
  pg_size_pretty(pg_indexes_size(c.oid)) AS indexes_size,
  pg_catalog.obj_description(c.oid, 'pg_class') as "Description"
FROM pg_catalog.pg_class c
     LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace
WHERE c.relkind IN ('r', 'i', 's', 'p', 'v', 'm', 'S', 'I', 'f')
      AND n.nspname <> 'pg_catalog'
      AND n.nspname <> 'information_schema'
      AND n.nspname !~ '^pg_toast'
      AND n.nspname <> 'oracle'
	    AND n.nspname <> 'tiger' 
ORDER BY pg_catalog.pg_table_size(c.oid) desc;

通过 pg_class 和 pg_namespace 查询当前数据库下所有用户对象(表、视图、索引、序列等)的信息,包括所属 Schema、对象名、对象类型、总大小(含索引和 TOAST)、对象本身大小和索引大小。

2.22 查看 schema 信息

sql 复制代码
--查询所有 schema
SELECT n.nspname AS "Name",
  pg_catalog.pg_get_userbyid(n.nspowner) AS "Owner"
FROM pg_catalog.pg_namespace n
ORDER BY 1;

--查询当前会话使用 schema
SELECT current_schema();

列出 database 下的 Schema 及其属主,并显示当前会话 search_path 中生效的 Schema(current_schema())。用于 Schema 权限梳理,以及排查「找不到表」类问题------对象解析依赖 search_path 的顺序。

2.23 database

按大小降序列出所有数据库的详细信息:名称、大小、编码、排序规则、是否允许连接、连接限制、所有者和当前连接总数。

通过 age(datfrozenxid) 查询每个数据库的事务年龄,与 autovacuum_freeze_max_age 参数对比,判断是否需要执行 VACUUM FREEZE 防止事务回卷。

sql 复制代码
--列出所有数据库基本信息,大小、编码、是否允许连接、连接限制、属主等
SELECT 
    datname AS database_name,
    pg_size_pretty(pg_database_size(datname)) AS size,
    pg_encoding_to_char(encoding) AS encoding,
    datcollate AS collation,
    datallowconn AS allow_connections,
    datconnlimit AS connection_limit,
    pg_get_userbyid(datdba) AS owner,
    (SELECT count(*) FROM pg_stat_activity WHERE datname = d.datname) AS total_connections
FROM pg_database d
ORDER BY pg_database_size(datname) DESC;

--查询数据库的年龄
SELECT datname, age(datfrozenxid) AS transaction_age, 
    current_setting('autovacuum_freeze_max_age')::int AS max_safe_age,
    CASE 
        WHEN age(datfrozenxid) > current_setting('autovacuum_freeze_max_age')::int 
        THEN 'WARNING: NEEDS VACUUM FREEZE' 
        ELSE 'OK' 
    END AS status
FROM pg_database;

2.24 表(table)相关

举例围绕表的运维查询:表统计信息(扫描次数、DML 计数、死元组、最近 vacuum/analyze 时间)、索引清单与使用统计、外键依赖、分区表边界与大小,表膨胀检测 SQL。用于表级健康体检、索引治理、分区维护与膨胀治理。表膨胀查询基于统计信息估算,结果仅供参考。

sql 复制代码
-- 查看表的统计信息
SELECT schemaname, relname, seq_scan, seq_tup_read, idx_scan, idx_tup_fetch, 
    n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, 
    last_vacuum, last_autovacuum, last_analyze, last_autoanalyze 
FROM pg_stat_user_tables
ORDER BY n_dead_tup DESC;

-- 查看表的索引信息
SELECT schemaname, tablename, indexname , indexdef 
FROM pg_indexes
WHERE schemaname NOT IN ('pg_catalog', 'information_schema')
ORDER BY schemaname, tablename, indexname;

-- 查看索引使用统计
SELECT schemaname, relname, indexrelname, idx_scan, idx_tup_read, idx_tup_fetch 
FROM pg_stat_user_indexes
ORDER BY idx_scan DESC;

-- 查看表之间的外键依赖关系
SELECT conname AS constraint_name, conrelid::regclass AS source_table, confrelid::regclass AS target_table, 
    pg_get_constraintdef(oid) AS constraint_definition
FROM pg_constraint
WHERE contype = 'f'
ORDER BY source_table, target_table;

-- 查看分区表信息
SELECT nmsp.nspname as schema_name, parent.relname as parent_table, child.relname as partition_name, 
    pg_get_expr(child.relpartbound, child.oid) AS partition_bound
FROM pg_inherits
JOIN pg_class parent ON pg_inherits.inhparent = parent.oid
JOIN pg_class child ON pg_inherits.inhrelid = child.oid
JOIN pg_namespace nmsp ON nmsp.oid = parent.relnamespace
WHERE parent.relkind = 'p'  -- 分区表
ORDER BY schema_name, parent_table, partition_name;

-- 查看分区表统计信息
SELECT schemaname, relname, pg_size_pretty(pg_total_relation_size(relid)) AS total_size,
    n_live_tup AS row_count, last_analyze
FROM pg_stat_user_tables
WHERE relname LIKE '%partition%'  -- 根据实际分区命名模式调整
ORDER BY pg_total_relation_size(relid) DESC;

-- 查看表的膨胀情况
SELECT schemaname, relname, pg_size_pretty(pg_relation_size(relid)) AS table_size,
    n_live_tup AS live_rows, n_dead_tup AS dead_rows, 
    CASE WHEN n_live_tup > 0 THEN ROUND((pg_relation_size(relid) / n_live_tup)::numeric, 2) ELSE 0 END AS avg_row_size,
    last_autovacuum
FROM pg_stat_user_tables
WHERE n_dead_tup > n_live_tup * 0.2  -- 死元组超过活元组的20%
ORDER BY (n_dead_tup::numeric / GREATEST(n_live_tup, 1)) DESC;

--表膨胀详细查询
WITH constants AS (
    SELECT current_setting('block_size')::numeric AS bs, 23 AS hdr, 4 AS ma
  ), bloat_info AS (
    SELECT
      ma,bs,schemaname,tablename,
      (datawidth+(hdr+ma-(case when hdr%ma=0 THEN ma ELSE hdr%ma END)))::numeric AS datahdr,
      (maxfracsum*(nullhdr+ma-(case when nullhdr%ma=0 THEN ma ELSE nullhdr%ma END))) AS nullhdr2
    FROM (
      SELECT
        schemaname, tablename, hdr, ma, bs,
        SUM((1-null_frac)*avg_width) AS datawidth,
        MAX(null_frac) AS maxfracsum,
        hdr+(
          SELECT 1+count(*)/8
          FROM pg_stats s2
          WHERE null_frac<>0 AND s2.schemaname = s.schemaname AND s2.tablename = s.tablename
        ) AS nullhdr
      FROM pg_stats s, constants
      GROUP BY 1,2,3,4,5
    ) AS foo
  ), table_bloat AS (
    SELECT
      schemaname, tablename, cc.relpages, bs,
      CEIL((cc.reltuples*((datahdr+ma-
        (CASE WHEN datahdr%ma=0 THEN ma ELSE datahdr%ma END))+nullhdr2+4))/(bs-20::float)) AS otta
    FROM bloat_info
    JOIN pg_class cc ON cc.relname = bloat_info.tablename
    JOIN pg_namespace nn ON cc.relnamespace = nn.oid AND nn.nspname = bloat_info.schemaname 
      AND nn.nspname <> 'information_schema'
  ), index_bloat AS (
    SELECT
      schemaname, tablename, bs,
      COALESCE(c2.relname,'?') AS iname, COALESCE(c2.reltuples,0) AS ituples, COALESCE(c2.relpages,0) AS ipages,
      COALESCE(CEIL((c2.reltuples*(datahdr-12))/(bs-20::float)),0) AS iotta 
    FROM bloat_info
    JOIN pg_class cc ON cc.relname = bloat_info.tablename
    JOIN pg_namespace nn ON cc.relnamespace = nn.oid 
      AND nn.nspname = bloat_info.schemaname 
      AND nn.nspname <> 'information_schema'
    JOIN pg_index i ON indrelid = cc.oid
    JOIN pg_class c2 ON c2.oid = i.indexrelid
  )
  SELECT
    current_database(),type, schemaname, object_name, bloat, pg_size_pretty(raw_waste::bigint) as waste
  FROM
  (SELECT 'table' as type, schemaname, tablename as object_name,
    ROUND(CASE WHEN otta=0 THEN 0.0 ELSE table_bloat.relpages/otta::numeric END,1) AS bloat,
    CASE WHEN relpages < otta THEN '0' ELSE (bs*(table_bloat.relpages-otta)::bigint)::bigint END AS raw_waste
  FROM table_bloat
      UNION
  SELECT 'index' as type, schemaname, tablename || '::' || iname as object_name,
    ROUND(CASE WHEN iotta=0 OR ipages=0 THEN 0.0 ELSE ipages/iotta::numeric END,1) AS bloat,
    CASE WHEN ipages < iotta THEN '0' ELSE (bs*(ipages-iotta))::bigint END AS raw_waste
  FROM index_bloat) bloat_summary
  ORDER BY bloat DESC limit 100;
--ORDER BY bloat_summary.raw_waste DESC limit 50;

2.25 autovacuum 信息

多个维度查询 autovacuum:各表 vacuum/analyze 时间与次数、死元组比例、当前正在运行的 autovacuum 进程、清理性能统计、潜在问题诊断、长时间运行的 autovacuum 以及优化建议。用于判断 autovacuum 是否正常工作、死元组是否堆积、是否需要调整参数或手工 VACUUM,是防止表膨胀与事务回卷的核心查询监控。

sql 复制代码
-- 查看 autovacuum 信息
SELECT schemaname AS schema_name, relname AS table_name, 
    last_vacuum, last_autovacuum, last_analyze, last_autoanalyze,
    vacuum_count, autovacuum_count, analyze_count, autoanalyze_count,
    n_live_tup AS live_rows, n_dead_tup AS dead_rows, 
    ROUND((n_dead_tup::numeric / GREATEST(n_live_tup + n_dead_tup, 1)) * 100, 2) AS dead_row_percentage
FROM pg_stat_user_tables
ORDER BY dead_row_percentage DESC
NULLS LAST;

-- 查看需要 autovacuum 的表(死元组比例高)
SELECT schemaname AS schema_name, relname AS table_name, n_live_tup AS live_rows, n_dead_tup AS dead_rows,
    ROUND((n_dead_tup::numeric / GREATEST(n_live_tup, 1)) * 100, 2) AS dead_row_ratio,
    last_autovacuum, now() - last_autovacuum AS time_since_last_autovacuum 
FROM pg_stat_user_tables
WHERE n_dead_tup > 1000
ORDER BY dead_row_ratio DESC
LIMIT 20;

-- 查看当前正在运行的 autovacuum 进程
SELECT pid, datname, usename, application_name, client_addr, backend_start, query_start, 
    state, query, wait_event_type, wait_event 
FROM pg_stat_activity 
WHERE 
    (query LIKE '%autovacuum%' 
     OR query LIKE '%VACUUM%' 
     OR backend_type = 'autovacuum worker')
    AND pid != pg_backend_pid()
ORDER BY query_start;

-- 查看 autovacuum 性能统计
SELECT schemaname AS schema_name, relname AS table_name, autovacuum_count, autoanalyze_count, 
    CASE WHEN autovacuum_count > 0 THEN ROUND(CAST(n_dead_tup::numeric / autovacuum_count AS numeric), 2)
        ELSE NULL
    END AS avg_dead_tup_per_vacuum,
    CASE WHEN last_autovacuum IS NOT NULL AND autovacuum_count > 0 THEN 
            ROUND(CAST(EXTRACT(EPOCH FROM (now() - last_autovacuum)) / 3600 / autovacuum_count AS numeric), 2)
        ELSE NULL 
    END AS hours_between_vacuums
FROM pg_stat_user_tables
WHERE autovacuum_count > 0
ORDER BY avg_dead_tup_per_vacuum DESC
LIMIT 20;

-- 查看长时间运行的 autovacuum
SELECT pid, datname, now() - query_start AS duration, query, wait_event_type, wait_event 
FROM pg_stat_activity 
WHERE (query LIKE '%autovacuum%' OR query LIKE '%VACUUM%')
  AND state = 'active'
  AND now() - query_start > interval '5 minutes'
ORDER BY duration DESC;

-- autovacuum 优化建议
SELECT schema_name, table_name, live_rows, dead_rows, dead_row_ratio, autovacuum_count, 
    CASE 
        WHEN live_rows > 1000000 AND dead_row_ratio > 10 THEN
            '考虑降低该表的 autovacuum_vacuum_scale_factor'
        WHEN autovacuum_count > 10 AND dead_row_ratio < 1 THEN
            '考虑增加该表的 autovacuum_vacuum_threshold'
        WHEN dead_rows > 100000 AND (now() - last_autovacuum) > interval '1 hour' THEN
            '检查 autovacuum 是否被阻塞,或考虑手动清理'
        ELSE '配置看起来是合适的'
    END AS recommendation
FROM (
    SELECT schemaname AS schema_name, relname AS table_name, n_live_tup AS live_rows, n_dead_tup AS dead_rows,
        ROUND((n_dead_tup::numeric / GREATEST(n_live_tup, 1)) * 100, 2) AS dead_row_ratio,
        autovacuum_count, last_autovacuum
    FROM pg_stat_user_tables
    WHERE n_live_tup > 10000
) AS subquery
ORDER BY dead_row_ratio DESC
LIMIT 20;

2.26 锁排查相关SQL

锁诊断工具链:pg_locks 全量锁、等待中的锁、锁等待链(谁阻塞谁)、特定表/所有用户表的锁、长事务持有的锁、事务 ID 锁、锁等待统计、锁模式分布、锁竞争环检查、deadlock_timeout配置等,当数据库出现查询卡住、应用超时或大量 waiting 时,按「先看等待锁 → 定位阻塞者 → 查长事务 → 决定是否终止」的顺序使用。

sql 复制代码
-- 查看当前所有活动锁
SELECT locktype, database, relation, page, tuple, virtualxid, transactionid, classid, objid, objsubid,
    virtualtransaction, pid, mode, granted, fastpath 
FROM pg_locks
ORDER BY locktype, database, relation;

-- 查看当前未授予的锁(等待中的锁)
SELECT l.locktype, l.mode, l.pid AS waiting_pid, l.granted, a.usename, a.query, a.state AS waiting_state
FROM pg_locks l
JOIN pg_stat_activity a ON l.pid = a.pid
WHERE NOT l.granted
ORDER BY l.pid;

-- 查看锁等待链(谁在等待谁)
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,
    blocking_activity.query AS current_statement_in_blocking_process,
    blocked_locks.mode AS blocked_lock_mode,
    blocking_locks.mode AS blocking_lock_mode,
    blocked_locks.locktype AS lock_type,
    now() - blocked_activity.query_start AS blocked_duration,
    now() - blocking_activity.query_start AS blocking_duration
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 AND blocking_locks.granted
ORDER BY blocked_duration DESC;

-- 查看特定表上的锁
SELECT 
    l.pid AS process_id,
    a.usename AS username,
    a.datname AS database_name,
    l.mode AS lock_mode,
    l.granted AS is_granted,
    a.query AS query_text,
    a.query_start AS query_start_time,
    a.state AS query_state,
    a.client_addr AS client_address,
    a.application_name
FROM pg_locks l
JOIN pg_stat_activity a ON l.pid = a.pid
JOIN pg_class c ON l.relation = c.oid
WHERE c.relname = 'your_table_name'  -- 替换为实际的表名
ORDER BY l.granted, l.pid;

-- 查看所有表上的锁及其关联查询
SELECT 
    n.nspname AS schema_name,
    c.relname AS table_name,
    l.mode AS lock_mode,
    l.granted AS is_granted,
    a.pid AS process_id,
    a.usename AS username,
    a.query AS query_text,
    a.state AS query_state,
    a.wait_event_type AS wait_type,
    a.wait_event AS wait_event
FROM pg_locks l
JOIN pg_class c ON l.relation = c.oid
JOIN pg_namespace n ON c.relnamespace = n.oid
LEFT JOIN pg_stat_activity a ON l.pid = a.pid
WHERE l.locktype = 'relation' AND n.nspname NOT LIKE 'pg_%'
ORDER BY n.nspname, c.relname, l.granted;

-- 查看长时间运行的事务及其持有的锁
SELECT 
    a.pid AS process_id,
    a.usename AS username,
    a.datname AS database_name,
    a.query AS query_text,
    a.xact_start AS transaction_start,
    now() - a.xact_start AS transaction_duration,
    l.locktype AS lock_type,
    l.mode AS lock_mode,
    l.granted AS is_granted,
    CASE 
        WHEN l.relation IS NOT NULL THEN 
            (SELECT nspname || '.' || relname 
            FROM pg_class c 
            JOIN pg_namespace n 
            ON c.relnamespace = n.oid 
            WHERE c.oid = l.relation)
        ELSE NULL 
    END AS locked_object
FROM pg_stat_activity a
JOIN pg_locks l ON a.pid = l.pid
WHERE a.xact_start IS NOT NULL AND now() - a.xact_start > interval '5 minutes' 
ORDER BY transaction_duration DESC;

-- 查看事务ID锁
SELECT 
    l.pid AS process_id,
    a.usename AS username,
    l.transactionid AS transaction_id,
    l.mode AS lock_mode,
    l.granted AS is_granted,
    a.query AS query_text,
    a.xact_start AS transaction_start,
    now() - a.xact_start AS transaction_duration
FROM pg_locks l
JOIN pg_stat_activity a ON l.pid = a.pid
WHERE l.locktype = 'transactionid'
ORDER BY l.transactionid::text, l.granted DESC;

-- 查看锁等待统计
SELECT wait_event_type, wait_event, COUNT(*) AS waiting_sessions, 
    SUM(EXTRACT(EPOCH FROM (now() - state_change))) AS total_wait_seconds,
    AVG(EXTRACT(EPOCH FROM (now() - state_change))) AS avg_wait_seconds,
    MAX(EXTRACT(EPOCH FROM (now() - state_change))) AS max_wait_seconds
FROM pg_stat_activity
WHERE wait_event_type IS NOT NULL AND wait_event_type LIKE '%Lock%'
GROUP BY wait_event_type, wait_event
ORDER BY total_wait_seconds DESC;

-- 查看最常见的锁模式
SELECT mode AS lock_mode,
    COUNT(*) AS lock_count,
    COUNT(*) FILTER (WHERE granted) AS granted_count,
    COUNT(*) FILTER (WHERE NOT granted) AS waiting_count,
    locktype AS lock_type
FROM pg_locks
GROUP BY mode, locktype
ORDER BY lock_count DESC;

-- 检查可能的死锁情况(需要定期执行)
SELECT 
    a1.pid AS process1_id,
    a1.usename AS process1_user,
    a1.query AS process1_query,
    a2.pid AS process2_id,
    a2.usename AS process2_user,
    a2.query AS process2_query,
    l1.mode AS process1_lock_mode,
    l2.mode AS process2_lock_mode,
    CASE 
        WHEN l1.relation IS NOT NULL THEN 
            (SELECT nspname || '.' || relname 
            FROM pg_class c 
            JOIN pg_namespace n ON c.relnamespace = n.oid 
            WHERE c.oid = l1.relation)
        ELSE 'Transaction ID: ' || l1.transactionid::text
    END AS locked_object
FROM pg_locks l1
JOIN pg_locks l2 ON 
    (l1.relation = l2.relation OR l1.transactionid = l2.transactionid)
    AND l1.pid != l2.pid
JOIN pg_stat_activity a1 ON l1.pid = a1.pid
JOIN pg_stat_activity a2 ON l2.pid = a2.pid
WHERE NOT l1.granted AND NOT l2.granted
AND l1.pid < l2.pid  -- 避免重复
ORDER BY locked_object;

-- 查看死锁检测配置
SELECT name, setting, unit, short_desc AS description 
FROM pg_settings WHERE name = 'deadlock_timeout';

-- 查看每个会话的锁信息
SELECT 
    a.pid AS process_id,
    a.usename AS username,
    a.datname AS database_name,
    a.application_name,
    a.client_addr AS client_address,
    COUNT(l.*) AS total_locks,
    COUNT(l.*) FILTER (WHERE l.granted) AS granted_locks,
    COUNT(l.*) FILTER (WHERE NOT l.granted) AS waiting_locks,
    a.query AS current_query,
    a.state AS query_state,
    a.wait_event_type AS wait_type,
    a.wait_event AS wait_event
FROM pg_stat_activity a
LEFT JOIN pg_locks l ON a.pid = l.pid
WHERE a.pid <> pg_backend_pid()  -- 排除当前会话
GROUP BY a.pid, a.usename, a.datname, a.application_name, a.client_addr, 
    a.query, a.state, a.wait_event_type, a.wait_event  
ORDER BY waiting_locks DESC, total_locks DESC;

-- 查看锁相关的系统视图和函数
SELECT n.nspname AS schema_name, c.relname AS object_name,
    CASE c.relkind WHEN 'r' THEN 'table' WHEN 'v' THEN 'view' WHEN 'f' THEN 'foreign table' ELSE 'other' END AS object_type, 
    obj_description(c.oid) AS description
FROM pg_class c
JOIN pg_namespace n ON c.relnamespace = n.oid
WHERE c.relname LIKE '%lock%'
AND n.nspname IN ('pg_catalog', 'information_schema')
ORDER BY n.nspname, c.relname;

-- 查看锁模式的定义
SELECT DISTINCT mode FROM pg_locks;

-- 生成锁问题诊断报告
SELECT '当前活动锁总数: ' AS metric, COUNT(*)::text AS value FROM pg_locks
UNION ALL
SELECT '等待中的锁数量: ', COUNT(*)::text FROM pg_locks WHERE NOT granted
UNION ALL
SELECT 
    '最长锁等待时间(秒): ',
    COALESCE(MAX(EXTRACT(EPOCH FROM (now() - state_change)))::text, '0')
FROM pg_stat_activity
WHERE wait_event_type LIKE '%Lock%'
UNION ALL
SELECT 
    '平均锁等待时间(秒): ',
    COALESCE(AVG(EXTRACT(EPOCH FROM (now() - state_change)))::text, '0')
FROM pg_stat_activity
WHERE wait_event_type LIKE '%Lock%'
UNION ALL
SELECT 
    '可能死锁情况: ',
    COUNT(DISTINCT blocked.pid)::text
FROM (
    SELECT DISTINCT l1.pid
    FROM pg_locks l1
    JOIN pg_locks l2 ON 
        (l1.relation = l2.relation OR l1.transactionid = l2.transactionid)
        AND l1.pid != l2.pid
    WHERE NOT l1.granted AND NOT l2.granted
) AS blocked;

2.27 流复制和逻辑复制相关SQL

流复制与逻辑复制的查询监控:备库判断(pg_is_in_recovery)、WAL 接收进程、收发 LSN 对比、复制相关配置参数、pg_stat_replication 备库状态与字节级延迟、WAL 位置与平均生成速率、复制吞吐量(两次采样)、复制槽信息、同步复制状态、健康检查与问题诊断、阻塞复制的长事务,以及逻辑复制订阅与发布状态。用于主备同步监控、复制延迟与冲突排查、复制槽清理(防止 WAL 堆积)和逻辑复制故障排查。

sql 复制代码
--查询是否备库
SELECT pg_is_in_recovery();

--查看wal接收进程状态
SELECT * FROM pg_stat_wal_receiver;
--对比接收和应用的LSN号
SELECT
    pg_last_wal_receive_lsn() AS last_received,
    pg_last_wal_replay_lsn() AS last_applied,
    pg_last_xact_replay_timestamp() AS last_applied_ts;

-- 查看复制相关配置参数
SELECT name, setting, unit, short_desc AS description
FROM pg_settings 
WHERE name LIKE '%replication%'
   OR name LIKE '%wal%'
   OR name LIKE '%archive%'
   OR name LIKE '%recovery%'
   OR name LIKE '%standby%'
   OR name IN ('max_wal_senders', 'hot_standby', 'wal_level', 'max_replication_slots')
ORDER BY name;

-- 查看主库上的流复制连接状态
SELECT pid, usename, application_name, client_addr, client_hostname, client_port, backend_start,
    state, sync_state, sync_priority, write_lag, flush_lag, replay_lag,
    write_lag + flush_lag + replay_lag AS total_lag
FROM pg_stat_replication
ORDER BY sync_priority, application_name;

-- 查看主库的流复制配置摘要
SELECT 
    (SELECT setting FROM pg_settings WHERE name = 'wal_level') AS wal_level,
    (SELECT setting FROM pg_settings WHERE name = 'max_wal_senders') AS max_wal_senders,
    (SELECT setting FROM pg_settings WHERE name = 'max_replication_slots') AS max_replication_slots,
    (SELECT setting FROM pg_settings WHERE name = 'hot_standby') AS hot_standby,
    (SELECT COUNT(*) FROM pg_stat_replication) AS active_replication_connections,
    (SELECT COUNT(*) FROM pg_replication_slots) AS replication_slots_defined;

-- 查看最近的流复制冲突详情
SELECT now() - query_start AS conflict_age, usename, datname, query, wait_event_type, wait_event
FROM pg_stat_activity 
WHERE wait_event_type = 'Client'
  AND wait_event = 'ClientRead'
  AND state = 'idle in transaction'
ORDER BY query_start;

--查看所有备库的详细状态和延迟
SELECT application_name, client_addr, state, sync_state, write_lag, flush_lag, replay_lag,
    -- 精确计算延迟(字节)
    pg_wal_lsn_diff(pg_current_wal_lsn(), sent_lsn) AS not_sent_bytes,
    pg_wal_lsn_diff(sent_lsn, write_lsn) AS not_written_bytes,
    pg_wal_lsn_diff(write_lsn, flush_lsn) AS not_flushed_bytes,
    pg_wal_lsn_diff(flush_lsn, replay_lsn) AS not_applied_bytes,
    pg_wal_lsn_diff(pg_current_wal_lsn(), replay_lsn) AS total_lag_bytes,
    -- 转换为MB
    (pg_wal_lsn_diff(pg_current_wal_lsn(), replay_lsn) / (1024.0 * 1024.0))::numeric(10,2) AS total_lag_mb
FROM
    pg_stat_replication;

-- 计算复制吞吐量
WITH replication_stats AS (
    SELECT 
        application_name,
        pg_wal_lsn_diff(pg_current_wal_lsn(), replay_lsn) AS current_lag_bytes,
        pg_wal_lsn_diff(pg_current_wal_lsn(), replay_lsn) - 
        LAG(pg_wal_lsn_diff(pg_current_wal_lsn(), replay_lsn)) 
          OVER (PARTITION BY application_name ORDER BY now()) AS lag_change_bytes,
        EXTRACT(
          EPOCH FROM (now() - LAG(now()) OVER (PARTITION BY application_name ORDER BY now()))
        ) AS time_interval_seconds
    FROM pg_stat_replication
)
SELECT application_name, current_lag_bytes,
    CASE 
        WHEN time_interval_seconds > 0 THEN 
            ROUND(CAST(lag_change_bytes / time_interval_seconds / 1024 / 1024 AS numeric), 2)
        ELSE 0 
    END AS replication_rate_mb_per_second
FROM replication_stats
WHERE lag_change_bytes IS NOT NULL
ORDER BY replication_rate_mb_per_second DESC;

-- 查看当前WAL位置信息
SELECT 
    pg_current_wal_lsn() AS current_lsn,
    pg_walfile_name(pg_current_wal_lsn()) AS current_wal_file,
    pg_wal_lsn_diff(pg_current_wal_lsn(), '0/0') AS total_wal_bytes;

-- 查看流复制位置对比
SELECT 
    application_name,
    pg_current_wal_lsn() AS current_master_lsn,
    sent_lsn AS last_sent_lsn,
    write_lsn AS last_write_lsn,
    flush_lsn AS last_flush_lsn,
    replay_lsn AS last_replay_lsn,
    pg_wal_lsn_diff(pg_current_wal_lsn(), replay_lsn) AS replication_lag_bytes,
    pg_size_pretty(pg_wal_lsn_diff(pg_current_wal_lsn(), replay_lsn)) AS replication_lag
FROM pg_stat_replication;

--查询复制槽信息
SELECT slot_name, plugin, slot_type, datoid, database, active, restart_lsn, confirmed_flush_lsn 
FROM pg_replication_slots;

-- 查看复制槽的详细统计信息
SELECT slot_name, spill_txns, spill_count, spill_bytes, stream_txns, stream_count, stream_bytes 
FROM pg_stat_replication_slots;

-- 查看同步复制状态
SELECT application_name, sync_state, sync_priority,
    CASE 
        WHEN sync_state = 'sync' THEN '同步复制节点'
        WHEN sync_state = 'potential' THEN '潜在同步节点'
        WHEN sync_state = 'async' THEN '异步复制节点'
        ELSE sync_state
    END AS sync_status_description
FROM pg_stat_replication
ORDER BY sync_priority;

-- 检查同步复制配置
SELECT name, setting,
    CASE 
        WHEN name = 'synchronous_standby_names' AND setting = '' THEN '警告: 未配置同步备库'
        WHEN name = 'synchronous_commit' AND setting = 'off' THEN '警告: 同步提交已关闭'
        ELSE '正常'
    END AS status
FROM pg_settings 
WHERE name IN ('synchronous_standby_names', 'synchronous_commit');

-- 流复制健康检查报告
SELECT '活跃复制连接数', COUNT(*)::text FROM pg_stat_replication
UNION ALL
SELECT '最大复制延迟(秒)', COALESCE(MAX(EXTRACT(EPOCH FROM (write_lag + flush_lag + replay_lag)))::text, '0')
FROM pg_stat_replication
UNION ALL
SELECT '复制槽数量', COUNT(*)::text FROM pg_replication_slots
UNION ALL
SELECT '未使用的复制槽', COUNT(*) FILTER (WHERE active = false)::text FROM pg_replication_slots
UNION ALL
SELECT '同步复制配置',
    COALESCE(
        (SELECT setting FROM pg_settings WHERE name = 'synchronous_standby_names'),
        '未配置'
    );

-- 流复制详细的健康状态检查
SELECT application_name, client_addr, sync_state, state, replay_lag, 
    now() - reply_time AS since_last_heartbeat
FROM pg_stat_replication
ORDER BY application_name;

-- 查找可能阻塞复制的长事务
SELECT pid, usename, datname, query, now() - xact_start AS transaction_age, now() - query_start AS query_age, state 
FROM pg_stat_activity 
WHERE state = 'active' AND (now() - xact_start) > interval '5 minutes' 
ORDER BY transaction_age DESC;

-- 查看逻辑复制状态
SELECT subname, received_lsn, last_msg_send_time, last_msg_receipt_time, latest_end_lsn, latest_end_time
FROM pg_stat_subscription;

-- 查看逻辑复制发布(在主库执行)
SELECT oid, pubname, pubowner::regrole AS owner, puballtables, pubinsert, pubupdate, pubdelete, pubtruncate 
FROM pg_publication
ORDER BY pubname;

3.总结

本文系统梳理了瀚高数据库V9中常用系统表/视图以及日常运维中最高频的查询SQL,涵盖以下内容:

1、对核心系统表逐一说明作用,方便快速定位所需元数据。

2、用户表、索引、视图、物化视图、序列、函数/存储过程、约束、触发器的完整查询语句,覆盖DBA日常上线审核和巡检需求。

3、数据库大小、表空间、表级空间占用(含索引和 TOAST)查询,结合表膨胀检测SQL,及时发现空间异常。

4、连接数分布(活跃/空闲/长事务)、锁等待链分析、死锁检测,快速定位并发问题。

5

死元组比例、autovacuum 运行状态、优化建议查询,防止表膨胀和事务回卷。

流复制延迟(字节级精确计算)、复制槽监控、同步/异步状态诊断、逻辑复制发布与订阅状态,确保主备同步健康。

数据库事务年龄查询,预警事务回卷风险。

相关推荐
ben9518chen1 小时前
mysql数据库基本操作
数据库·mysql
2603_965148111 小时前
电商选品调研:通过关键词搜索API获取市场热销商品,结合商品详情API分析竞品卖点与定价
开发语言·数据库·人工智能·python·信息可视化
土豆.exe2 小时前
nf_tables 的 verdict 被读了两次:一个十年未闭合的位域错配
java·数据库·网络安全·缓存
缓慢更新2 小时前
表单引擎的存储建模:宽表与文档库的取舍
运维·服务器·网络·数据库·低代码·oracle·适配器模式
Web3&Basketball4 小时前
实测Gemini4Argon:ERQA 87%登顶长程任务榜
数据库·python·大模型·多模态·gemini·长上下文·推理优化
xiaogai_gai4 小时前
金蝶收料通知单查询策略实战教程:从源系统拉取到中间层落地的完整路径
java·前端·数据库
注塑机数据采集联网4 小时前
注塑机数据采集网关对接MES系统数字化技术方案
大数据·网络·数据库·物联网·数据挖掘·数据分析
像风一样自由20205 小时前
56.实战PostgreSQL-pgvector-FastAPI构建轻量级RAG
数据库·人工智能·postgresql·大模型·fastapi·智能体
User_芊芊君子5 小时前
KFS异构同步_260条链路DDL自动转换解析
数据库·ai·大模型