1. 首页 > PostgreSQL教程 > 正文

PostgreSQL教程FG135-PG系统视图与信息模式的区别与使用

本文档风哥主要介绍PostgreSQL系统视图与信息模式的区别和使用场景,帮助DBA和开发人员选择合适的方式访问数据库元数据,风哥教程参考PostgreSQL官方文档。

from oracle:www.itpux.com

Part01-基础概念与理论知识

1.1 系统视图与信息模式概述

PostgreSQL提供两种访问数据库元数据的方式:系统目录(System Catalogs)和信息模式(Information Schema)。更多视频教程www.fgedu.net.cn

系统目录:

  • PostgreSQL特有的元数据存储方式
  • 位于pg_catalog模式中
  • 提供完整的元数据信息
  • 性能较好

信息模式:

  • SQL标准定义的元数据视图
  • 位于information_schema模式中
  • 提供标准化的元数据接口
  • 跨数据库兼容

1.2 关键区别

— 系统目录与信息模式的关键区别

— 1. 可移植性
— 系统目录:PostgreSQL特有,不可移植
— 信息模式:SQL标准,可移植到其他数据库

— 2. 性能
— 系统目录:直接访问系统表,性能更好
— 信息模式:基于系统目录的视图,性能稍差

— 3. 功能
— 系统目录:功能更全面,包含PostgreSQL特有信息
— 信息模式:功能标准化,可能缺少PostgreSQL特有信息

— 4. 稳定性
— 系统目录:可能随版本变化
— 信息模式:SQL标准,相对稳定

— 5. 权限
— 系统目录:需要特定权限访问某些表
— 信息模式:自动过滤用户无权访问的对象

1.3 使用场景

— 使用场景

— 使用系统目录的场景:
— 1. 需要PostgreSQL特有的元数据信息
— 2. 对性能要求较高
— 3. 不需要跨数据库移植
— 4. 需要访问索引、统计信息等

— 使用信息模式的场景:
— 1. 需要跨数据库移植的代码
— 2. 只需要标准的元数据信息
— 3. 希望自动过滤无权访问的对象
— 4. 编写通用的数据库工具

— 混合使用的场景:
— 1. 结合两者的优势
— 2. 使用信息模式获取标准信息
— 3. 使用系统目录获取PostgreSQL特有信息

风哥提示:选择系统目录还是信息模式取决于具体需求,理解两者的区别有助于做出正确的选择。学习交流加群风哥微信: itpux-com

Part02-生产环境规划与建议

2.1 系统目录详解

2.1.1 主要系统表

— 主要系统表

— 1. pg_class: 表、索引、序列等对象
SELECT relname, relkind, reltuples
FROM pg_class
WHERE relkind = ‘r’
LIMIT 5;

— 2. pg_attribute: 列信息
SELECT attname, atttypid::regtype, attnotnull
FROM pg_attribute
WHERE attrelid = ‘fgedu_employees’::regclass;

— 3. pg_type: 数据类型
SELECT typname, typtype
FROM pg_type
WHERE typtype = ‘b’
LIMIT 10;

— 4. pg_constraint: 约束
SELECT conname, contype
FROM pg_constraint
WHERE conrelid = ‘fgedu_employees’::regclass;

— 5. pg_index: 索引
SELECT indexrelid::regclass, indisprimary, indisunique
FROM pg_index
WHERE indrelid = ‘fgedu_employees’::regclass;

2.2 信息模式详解

2.2.1 主要信息模式视图

— 主要信息模式视图

— 1. tables: 表信息
SELECT table_name, table_type
FROM information_schema.tables
WHERE table_schema = ‘public’;

— 2. columns: 列信息
SELECT column_name, data_type, is_nullable
FROM information_schema.columns
WHERE table_name = ‘fgedu_employees’;

— 3. table_constraints: 约束
SELECT constraint_name, constraint_type
FROM information_schema.table_constraints
WHERE table_name = ‘fgedu_employees’;

— 4. key_column_usage: 键列
SELECT column_name, constraint_name
FROM information_schema.key_column_usage
WHERE table_name = ‘fgedu_employees’;

— 5. referential_constraints: 外键
SELECT constraint_name, unique_constraint_name
FROM information_schema.referential_constraints;

2.3 选择标准

— 选择标准

— 1. 需要索引信息 -> 使用系统目录
SELECT indexname, indexdef
FROM pg_indexes
WHERE tablename = ‘fgedu_employees’;

— 2. 需要跨数据库兼容 -> 使用信息模式
SELECT table_name, column_name, data_type
FROM information_schema.columns
WHERE table_name = ‘fgedu_employees’;

— 3. 需要统计信息 -> 使用系统目录
SELECT relname, reltuples, relpages
FROM pg_class
WHERE relname = ‘fgedu_employees’;

— 4. 需要权限信息 -> 两者都可以
— 系统目录方式
SELECT relacl FROM pg_class WHERE relname = ‘fgedu_employees’;

— 信息模式方式
SELECT grantee, privilege_type
FROM information_schema.table_privileges
WHERE table_name = ‘fgedu_employees’;

风哥教程针对风哥教程针对风哥教程针对生产环境建议:在生产环境中,建议根据具体需求选择合适的方式。如果需要跨数据库兼容性,使用信息模式;如果需要PostgreSQL特有的功能或更好的性能,使用系统目录。学习交流加群风哥QQ113257174

Part03-生产环境项目实施方案

3.1 系统目录查询

3.1.1 常用系统目录查询

— 常用系统目录查询

— 1. 查询所有表及其大小
SELECT
c.relname as table_name,
pg_size_pretty(pg_total_relation_size(c.oid)) as total_size,
pg_size_pretty(pg_relation_size(c.oid)) as table_size,
pg_size_pretty(pg_indexes_size(c.oid)) as index_size,
c.reltuples::bigint as row_count
FROM pg_class c
JOIN pg_namespace n ON n.oid = c.relnamespace
WHERE c.relkind = ‘r’
AND n.nspname = ‘public’
ORDER BY pg_total_relation_size(c.oid) DESC;

— 2. 查询所有索引
SELECT
schemaname,
tablename,
indexname,
pg_size_pretty(pg_relation_size(indexrelid)) as index_size
FROM pg_indexes
WHERE schemaname = ‘public’
ORDER BY pg_relation_size(indexrelid) DESC;

— 3. 查询表的所有列详细信息
SELECT
a.attname as column_name,
t.typname as data_type,
a.attnotnull as not_null,
pg_get_expr(d.adbin, d.adrelid) as default_value,
CASE WHEN pk.attname IS NOT NULL THEN ‘PK’ ELSE ” END as is_primary_key
FROM pg_attribute a
JOIN pg_type t ON a.atttypid = t.oid
LEFT JOIN pg_attrdef d ON a.attrelid = d.adrelid AND a.attnum = d.adnum
LEFT JOIN (
SELECT a.attname
FROM pg_index i
JOIN pg_attribute a ON a.attrelid = i.indrelid AND a.attnum = ANY(i.indkey)
WHERE i.indrelid = ‘fgedu_employees’::regclass AND i.indisprimary
) pk ON a.attname = pk.attname
WHERE a.attrelid = ‘fgedu_employees’::regclass
AND a.attnum > 0
AND NOT a.attisdropped
ORDER BY a.attnum;

— 4. 查询外键关系
SELECT
tc.conname as constraint_name,
tc.conrelid::regclass as table_name,
kcu.column_name,
ccu.table_name as foreign_table_name,
ccu.column_name as foreign_column_name
FROM pg_constraint tc
JOIN information_schema.key_column_usage kcu
ON tc.conname = kcu.constraint_name
JOIN information_schema.constraint_column_usage ccu
ON ccu.constraint_name = tc.conname
WHERE tc.contype = ‘f’;

3.2 信息模式查询

3.2.1 常用信息模式查询

— 常用信息模式查询

— 1. 查询数据库中所有表
SELECT
table_schema,
table_name,
table_type
FROM information_schema.tables
WHERE table_schema NOT IN (‘pg_catalog’, ‘information_schema’)
ORDER BY table_schema, table_name;

— 2. 查询表的所有列
SELECT
column_name,
data_type,
character_maximum_length,
numeric_precision,
numeric_scale,
is_nullable,
column_default
FROM information_schema.columns
WHERE table_schema = ‘public’
AND table_name = ‘fgedu_employees’
ORDER BY ordinal_position;

— 3. 查询所有主键
SELECT
tc.table_name,
kcu.column_name,
tc.constraint_name
FROM information_schema.table_constraints tc
JOIN information_schema.key_column_usage kcu
ON tc.constraint_name = kcu.constraint_name
WHERE tc.constraint_type = ‘PRIMARY KEY’
AND tc.table_schema = ‘public’
ORDER BY tc.table_name;

— 4. 查询所有外键
SELECT
tc.table_name,
kcu.column_name,
ccu.table_name AS foreign_table_name,
ccu.column_name AS foreign_column_name,
tc.constraint_name
FROM information_schema.table_constraints tc
JOIN information_schema.key_column_usage kcu
ON tc.constraint_name = kcu.constraint_name
JOIN information_schema.constraint_column_usage ccu
ON ccu.constraint_name = tc.constraint_name
WHERE tc.constraint_type = ‘FOREIGN KEY’
AND tc.table_schema = ‘public’
ORDER BY tc.table_name;

3.3 混合使用方案

3.3.1 结合系统目录和信息模式

— 混合使用方案

— 1. 获取完整的表信息(结合两者)
SELECT
t.table_name,
t.table_type,
(SELECT COUNT(*) FROM information_schema.columns c
WHERE c.table_name = t.table_name) as column_count,
(SELECT COUNT(*) FROM information_schema.table_constraints tc
WHERE tc.table_name = t.table_name AND tc.constraint_type = ‘PRIMARY KEY’) as has_primary_key,
pg_size_pretty(pg_total_relation_size(t.table_schema || ‘.’ || t.table_name)) as total_size,
(SELECT reltuples::bigint FROM pg_class WHERE relname = t.table_name) as row_count
FROM information_schema.tables t
WHERE t.table_schema = ‘public’
AND t.table_type = ‘BASE TABLE’
ORDER BY pg_total_relation_size(t.table_schema || ‘.’ || t.table_name) DESC;

— 2. 生成表结构文档(结合两者)
SELECT
c.table_name,
c.column_name,
c.data_type ||
CASE
WHEN c.character_maximum_length IS NOT NULL
THEN ‘(‘ || c.character_maximum_length || ‘)’
ELSE ”
END as data_type,
CASE WHEN c.is_nullable = ‘NO’ THEN ‘NOT NULL’ ELSE ” END as nullable,
COALESCE(c.column_default, ”) as default_value,
COALESCE(
(SELECT ‘PK’ FROM pg_index i
JOIN pg_attribute a ON a.attrelid = i.indrelid AND a.attnum = ANY(i.indkey)
WHERE i.indrelid = (c.table_schema || ‘.’ || c.table_name)::regclass
AND i.indisprimary AND a.attname = c.column_name
LIMIT 1),

) as key_type
FROM information_schema.columns c
WHERE c.table_schema = ‘public’
ORDER BY c.table_name, c.ordinal_position;

风哥提示:混合使用系统目录和信息模式可以发挥两者的优势,获取更全面的元数据信息。更多学习教程公众号风哥教程itpux_com

Part04-生产案例与实战讲解

4.1 性能对比

4.1.1 查询性能测试

— 性能对比测试

— 测试1:查询所有表
— 系统目录方式
EXPLAIN ANALYZE
SELECT relname, relkind
FROM pg_class
WHERE relkind = ‘r’
AND relnamespace = ‘public’::regnamespace;

— 信息模式方式
EXPLAIN ANALYZE
SELECT table_name, table_type
FROM information_schema.tables
WHERE table_schema = ‘public’;

— 测试2:查询列信息
— 系统目录方式
EXPLAIN ANALYZE
SELECT a.attname, t.typname
FROM pg_attribute a
JOIN pg_type t ON a.atttypid = t.oid
WHERE a.attrelid = ‘fgedu_employees’::regclass
AND a.attnum > 0;

— 信息模式方式
EXPLAIN ANALYZE
SELECT column_name, data_type
FROM information_schema.columns
WHERE table_name = ‘fgedu_employees’;

— 性能结论:
— 系统目录通常更快,因为直接访问系统表
— 信息模式基于系统目录视图,有额外的开销
— 但对于大多数应用场景,性能差异可以忽略

4.2 使用案例

4.2.1 实际使用案例

— 使用案例

— 案例1:数据库文档生成工具
— 使用信息模式(跨数据库兼容)
CREATE OR REPLACE FUNCTION generate_documentation()
RETURNS TABLE (
table_name text,
column_name text,
data_type text,
is_nullable text,
constraint_type text
) AS $$
BEGIN
RETURN QUERY
SELECT
c.table_name::text,
c.column_name::text,
c.data_type::text,
c.is_nullable::text,
COALESCE(tc.constraint_type, ”)::text
FROM information_schema.columns c
LEFT JOIN information_schema.key_column_usage kcu
ON c.table_name = kcu.table_name AND c.column_name = kcu.column_name
LEFT JOIN information_schema.table_constraints tc
ON kcu.constraint_name = tc.constraint_name
WHERE c.table_schema = ‘public’
ORDER BY c.table_name, c.ordinal_position;
END;
$$ LANGUAGE plpgsql;

— 案例2:性能监控工具
— 使用系统目录(需要PostgreSQL特有信息)
CREATE OR REPLACE FUNCTION get_table_stats()
RETURNS TABLE (
table_name text,
row_count bigint,
table_size text,
index_size text,
total_size text
) AS $$
BEGIN
RETURN QUERY
SELECT
c.relname::text,
c.reltuples::bigint,
pg_size_pretty(pg_relation_size(c.oid))::text,
pg_size_pretty(pg_indexes_size(c.oid))::text,
pg_size_pretty(pg_total_relation_size(c.oid))::text
FROM pg_class c
JOIN pg_namespace n ON n.oid = c.relnamespace
WHERE c.relkind = ‘r’ AND n.nspname = ‘public’
ORDER BY pg_total_relation_size(c.oid) DESC;
END;
$$ LANGUAGE plpgsql;

— 案例3:数据库迁移工具
— 使用信息模式(跨数据库兼容)
CREATE OR REPLACE FUNCTION get_create_table_sql(p_table_name text)
RETURNS text AS $$
DECLARE
v_sql text;
v_columns text;
BEGIN
SELECT STRING_AGG(
column_name || ‘ ‘ || data_type ||
CASE WHEN is_nullable = ‘NO’ THEN ‘ NOT NULL’ ELSE ” END,
‘, ‘
)
INTO v_columns
FROM information_schema.columns
WHERE table_name = p_table_name
AND table_schema = ‘public’
ORDER BY ordinal_position;

v_sql := ‘CREATE TABLE fgedu_’ || p_table_name || ‘ (‘ || v_columns || ‘);’;
RETURN v_sql;
END;
$$ LANGUAGE plpgsql;

4.3 最佳实践

— 最佳实践

— 1. 优先使用信息模式获取标准元数据
— 优点:跨数据库兼容,自动过滤权限
SELECT table_name, column_name, data_type
FROM information_schema.columns
WHERE table_schema = ‘public’;

— 2. 使用系统目录获取PostgreSQL特有信息
— 优点:功能全面,性能更好
SELECT relname, reltuples, relpages
FROM pg_class
WHERE relkind = ‘r’;

— 3. 创建包装函数,统一接口
CREATE OR REPLACE FUNCTION get_tables()
RETURNS TABLE (table_name text, row_count bigint) AS $$
BEGIN
RETURN QUERY
SELECT c.relname::text, c.reltuples::bigint
FROM pg_class c
JOIN pg_namespace n ON n.oid = c.relnamespace
WHERE c.relkind = ‘r’ AND n.nspname = ‘public’;
END;
$$ LANGUAGE plpgsql;

— 4. 缓存不经常变化的元数据
— 创建元数据缓存表
CREATE TABLE fgedu_metadata_cache (
cache_key text PRIMARY KEY,
cache_value jsonb,
cached_at timestamp DEFAULT CURRENT_TIMESTAMP
);

— 5. 定期更新缓存
CREATE OR REPLACE FUNCTION refresh_metadata_cache()
RETURNS void AS $$
BEGIN
— 更新表列表缓存
INSERT INTO fgedu_metadata_cache (cache_key, cache_value)
SELECT ‘tables’, jsonb_agg(jsonb_build_object(
‘table_name’, table_name,
‘table_type’, table_type
))
FROM information_schema.tables
WHERE table_schema = ‘public’
ON CONFLICT (cache_key) DO UPDATE SET
cache_value = EXCLUDED.cache_value,
cached_at = CURRENT_TIMESTAMP;
END;
$$ LANGUAGE plpgsql;

风哥教程针对风哥教程针对风哥教程针对生产环境建议:在生产环境中,建议根据具体需求选择合适的方式。对于通用的元数据查询,使用信息模式;对于PostgreSQL特有的功能或性能敏感的查询,使用系统目录。from PostgreSQL:www.itpux.com

Part05-风哥经验总结与分享

5.1 决策指南

选择系统目录还是信息模式的决策指南:

— 决策指南

— 选择信息模式的情况:
— 1. 需要跨数据库兼容性
— 2. 编写通用的数据库工具
— 3. 只需要标准的元数据信息
— 4. 希望自动过滤无权访问的对象
— 5. 对性能要求不高

— 选择系统目录的情况:
— 1. 需要PostgreSQL特有的元数据
— 2. 需要索引、统计信息等
— 3. 对性能要求较高
— 4. 不需要跨数据库移植
— 5. 需要访问底层系统信息

— 混合使用的情况:
— 1. 结合两者的优势
— 2. 标准信息用信息模式
— 3. 特有信息用系统目录
— 4. 创建统一的接口层

5.2 常见陷阱

使用系统目录和信息模式的常见陷阱:

  • 权限问题:系统目录可能需要特定权限
  • 版本兼容性:系统目录结构可能随版本变化
  • 性能问题:复杂的信息模式查询可能较慢
  • 信息缺失:信息模式可能缺少某些PostgreSQL特有信息
  • 缓存问题:元数据缓存可能过期
风哥提示:理解系统目录和信息模式的优缺点,根据实际需求选择合适的方式,可以避免很多常见问题。

5.3 推荐方案

推荐的使用方案:

  • 开发通用工具:使用信息模式,确保跨数据库兼容
  • PostgreSQL专用工具:使用系统目录,获取完整功能
  • 性能敏感场景:使用系统目录,获得更好性能
  • 安全敏感场景:使用信息模式,自动过滤权限
  • 复杂查询场景:混合使用,发挥两者优势
持续学习:系统目录和信息模式都是访问数据库元数据的重要方式,建议深入学习和实践,掌握两者的使用技巧。

本文由风哥教程整理发布,仅用于学习测试使用,转载注明出处:http://www.fgedu.net.cn/10327.html

联系我们

在线咨询:点击这里给我发消息

微信号:itpux-com

工作日:9:30-18:30,节假日休息