在 PostgreSQL 的强大生态中,除了 DDL、DML、DQL、TCL、DCL 五大标准分类外,还存在大量高频使用、企业级必备、但不属于传统分类的 SQL 操作。这些操作往往决定系统的性能、可维护性、扩展性和安全性,却常被 Java 开发者忽视。
以下是一份专为 Java 后端开发者(尤其是使用 Spring Boot 的团队)撰写的 PostgreSQL 其他常用 SQL 操作深度详解文档,涵盖:序列管理、函数与触发器、CTE 递归查询、分区表、复制与导出、JSONB 聚合、全文检索增强、窗口函数进阶、系统视图与监控 等 9 大类,全部采用清晰中文注释式结构,提供标准、完整、可直接用于生产环境的示例,助你打造高性能、高可靠、易维护的企业级 PostgreSQL 架构。
🛠️ PostgreSQL 其他常用 SQL 操作深度详解文档
—— 超越五大分类的 9 大企业级核心能力
适用对象:Java 后端架构师、高级开发、DBA、技术负责人
目标:系统掌握 PostgreSQL 中不属于 DDL/DML/DQL/TCL/DCL 的 9 类高频、高价值 SQL 操作,补齐技术盲区,实现从“能用”到“精通” 的跨越,推动团队构建现代化、可扩展、高性能的数据层。
一、序列(SEQUENCE)—— 自增 ID 的“精密引擎”
说明:
BIGSERIAL是语法糖,本质是BIGINT+SEQUENCE。
企业价值:控制 ID 生成规则、支持自定义前缀、避免并发冲突。
✅ 标准使用示例(带中文注释)
-- 📌 示例1:创建自定义序列(推荐用于订单号、发票号等)
CREATE SEQUENCE order_seq
START WITH 1000000 -- ✅ 起始值,避免暴露系统内部ID
INCREMENT BY 1 -- ✅ 步长
MINVALUE 1000000 -- ✅ 最小值
MAXVALUE 9999999 -- ✅ 最大值(避免溢出)
CACHE 100 -- ✅ 缓存100个值,提升并发性能(减少磁盘I/O)
NO CYCLE; -- ✅ 不循环,避免重复(金融系统必须)
-- 📌 示例2:在插入时使用序列生成业务ID
INSERT INTO orders (order_no, user_id, total_amount)
VALUES (
'ORD-' || nextval('order_seq'), -- ✅ 生成:ORD-1000001
1001,
299.90
);
-- 📌 示例3:查看当前序列值
SELECT currval('order_seq'); -- ✅ 返回当前会话最后一次使用的值
-- 📌 示例4:重置序列(仅用于测试或初始化)
ALTER SEQUENCE order_seq RESTART WITH 1000000;
-- 📌 示例5:获取下一个值但不消费(仅查看)
SELECT nextval('order_seq'); -- ✅ 消费并返回下一个值
SELECT setval('order_seq', 999999); -- ✅ 手动设置当前值(慎用!)
-- 📌 示例6:为多个表共享一个序列(罕见,但可用于统一编号)
CREATE SEQUENCE global_id_seq START 1;
CREATE TABLE users (id BIGINT PRIMARY KEY DEFAULT nextval('global_id_seq'));
CREATE TABLE products (id BIGINT PRIMARY KEY DEFAULT nextval('global_id_seq'));
-- ✅ 用户ID和产品ID全局唯一,但可能不连续(如:用户1,产品2,用户3...)
✅ 团队规范建议:
- 业务 ID(如订单号、发票号)必须使用
SEQUENCE+ 字符串拼接,避免直接暴露BIGSERIAL。- 禁止使用
UUID作为人类可读的外部 ID(如订单号),应使用SEQUENCE生成。CACHE 100是性能关键,默认值 1 在高并发下是性能灾难。- 所有序列必须命名规范:
表名_字段名_seq。
二、函数(FUNCTION)与存储过程(PROCEDURE)—— 业务逻辑的“数据库内核”
说明:PostgreSQL 支持用
PL/pgSQL编写函数,将业务规则下沉到数据库层,提升一致性、减少网络开销。
✅ 标准使用示例(带中文注释)
-- 📌 示例1:创建函数:自动更新 updated_at(推荐!)
CREATE OR REPLACE FUNCTION update_updated_at_column()
RETURNS TRIGGER AS $$
BEGIN
NEW.updated_at = NOW(); -- ✅ 自动设置更新时间
RETURN NEW; -- ✅ 返回修改后的行
END;
$$ LANGUAGE plpgsql;
-- 📌 示例2:绑定函数到表(触发器)
CREATE TRIGGER trigger_users_update_updated_at
BEFORE UPDATE ON users
FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();
CREATE TRIGGER trigger_orders_update_updated_at
BEFORE UPDATE ON orders
FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();
-- ✅ 效果:Java 代码中无需写 `setUpdatedAt()`,数据库自动维护!
-- 📌 示例3:创建函数:计算用户总消费(可被查询复用)
CREATE OR REPLACE FUNCTION get_user_total_spent(user_id BIGINT)
RETURNS DECIMAL AS $$
DECLARE
total DECIMAL;
BEGIN
SELECT COALESCE(SUM(total_amount), 0)
INTO total
FROM orders
WHERE user_id = $1 AND status = 'paid';
RETURN total;
END;
$$ LANGUAGE plpgsql;
-- ✅ 使用:SELECT get_user_total_spent(1001); -- 一行 SQL 完成聚合
-- 📌 示例4:创建函数:返回多行结果(TABLE 类型)
CREATE OR REPLACE FUNCTION get_active_orders(user_id BIGINT)
RETURNS TABLE(order_no VARCHAR, total_amount DECIMAL, created_at TIMESTAMPTZ) AS $$
BEGIN
RETURN QUERY
SELECT o.order_no, o.total_amount, o.created_at
FROM orders o
WHERE o.user_id = $1 AND o.status = 'paid'
ORDER BY o.created_at DESC;
END;
$$ LANGUAGE plpgsql;
-- ✅ 使用:SELECT * FROM get_active_orders(1001); -- 像表一样查询
-- 📌 示例5:创建存储过程(PostgreSQL 11+)—— 用于复杂流程,无返回值
CREATE OR REPLACE PROCEDURE process_order_completion(order_id BIGINT)
LANGUAGE plpgsql
AS $$
DECLARE
order_status VARCHAR;
BEGIN
-- 查询当前状态
SELECT status INTO order_status FROM orders WHERE id = order_id;
IF order_status = 'paid' THEN
UPDATE orders SET status = 'shipped' WHERE id = order_id;
INSERT INTO order_events (order_id, event, created_at)
VALUES (order_id, 'shipped', NOW());
ELSE
RAISE EXCEPTION '订单状态不是已支付,无法发货';
END IF;
END;
$$;
-- ✅ 使用:CALL process_order_completion(12345);
✅ 团队规范建议:
- 所有“自动维护字段”(如
updated_at)必须用触发器 + 函数实现,Java 层不再写。- 所有复杂聚合、业务校验、状态机转换,优先写在数据库函数中。
- 函数必须命名清晰:
fn_前缀,如fn_calculate_discount。- 禁止在函数中执行 DDL 或长时间阻塞操作。
- 所有函数必须写注释,说明输入、输出、边界条件。
三、递归 CTE(Recursive CTE)—— 树形结构的“魔法查询”
说明:用于查询无限层级的树形结构(如组织架构、评论回复、菜单分类)。
✅ 标准使用示例(带中文注释)
-- 📌 示例:查询某个分类的所有子分类(无限层级)
-- 表结构:categories(id, name, parent_id)
WITH RECURSIVE category_tree AS (
-- ✅ 基础查询:从根节点开始(parent_id IS NULL)
SELECT id, name, parent_id, 0 AS level
FROM categories
WHERE id = 1 -- ✅ 从“电子产品”分类开始
UNION ALL
-- ✅ 递归部分:查找所有子节点
SELECT c.id, c.name, c.parent_id, ct.level + 1
FROM categories c
INNER JOIN category_tree ct ON c.parent_id = ct.id -- ✅ 关联父级
)
SELECT id, name, parent_id, level
FROM category_tree
ORDER BY level, name;
-- ✅ 输出:
-- id | name | parent_id | level
-- 1 | 电子产品 | NULL | 0
-- 2 | 手机 | 1 | 1
-- 3 | 笔记本 | 1 | 1
-- 4 | iPhone | 2 | 2
-- 5 | MacBook Pro | 3 | 2
-- 📌 示例2:查询某个评论的所有回复(嵌套评论)
-- 表结构:comments(id, content, parent_id, created_at)
WITH RECURSIVE comment_tree AS (
SELECT id, content, parent_id, created_at, 0 AS depth, ARRAY[id] AS path
FROM comments
WHERE id = 1001 -- ✅ 从主评论开始
UNION ALL
SELECT c.id, c.content, c.parent_id, c.created_at, ct.depth + 1, ct.path || c.id
FROM comments c
INNER JOIN comment_tree ct ON c.parent_id = ct.id
)
SELECT id, content, depth, path
FROM comment_tree
ORDER BY path; -- ✅ 按路径排序,保证层级顺序
✅ 团队规范建议:
- 所有树形结构(菜单、分类、评论、组织架构)必须用递归 CTE 查询。
- 禁止在 Java 中用循环递归查询,性能差、网络开销大。
- 使用
path数组记录路径,便于前端展开/折叠。- 限制递归深度:
SET max_recursion_depth = 100;防止死循环。
四、分区表(Partitioned Tables)—— 大数据量的“分而治之”
说明:将大表按时间、范围、列表拆分为多个物理子表,提升查询和维护性能。
✅ 标准使用示例(带中文注释)
-- 📌 示例1:创建按月分区的日志表(推荐用于日志、行为记录)
CREATE TABLE system_logs (
id BIGSERIAL,
event_time TIMESTAMPTZ NOT NULL,
level VARCHAR(10),
message TEXT,
user_id BIGINT
) PARTITION BY RANGE (event_time);
-- ✅ 创建第一个分区:2025年1月
CREATE TABLE system_logs_2025_01 PARTITION OF system_logs
FOR VALUES FROM ('2025-01-01') TO ('2025-02-01');
-- ✅ 创建第二个分区:2025年2月
CREATE TABLE system_logs_2025_02 PARTITION OF system_logs
FOR VALUES FROM ('2025-02-01') TO ('2025-03-01');
-- ✅ 插入数据:自动路由到对应分区
INSERT INTO system_logs (event_time, level, message, user_id)
VALUES ('2025-02-15 10:30:00', 'INFO', 'User login', 1001);
-- ✅ 查询:只扫描相关分区(性能提升 10x+)
SELECT * FROM system_logs
WHERE event_time >= '2025-02-01' AND event_time < '2025-03-01';
-- ✅ 删除旧数据:直接删除分区,瞬间完成(比 DELETE 快 1000 倍)
DROP TABLE system_logs_2024_12;
-- 📌 示例2:创建按状态分区的订单表
CREATE TABLE orders (
id BIGSERIAL,
status VARCHAR(20) NOT NULL,
created_at TIMESTAMPTZ,
total_amount DECIMAL
) PARTITION BY LIST (status);
CREATE TABLE orders_paid PARTITION OF orders FOR VALUES IN ('paid', 'shipped');
CREATE TABLE orders_pending PARTITION OF orders FOR VALUES IN ('pending', 'cancelled');
CREATE TABLE orders_deleted PARTITION OF orders FOR VALUES IN ('deleted');
-- ✅ 查询:只查已支付订单
SELECT * FROM orders_paid WHERE created_at > '2025-01-01';
✅ 团队规范建议:
- 所有日志表、行为表、历史表,超过 100 万行必须分区。
- 按时间分区(
RANGE)最常用,每月或每季一个分区。- 分区表的索引必须在每个分区上单独创建。
- 使用
pg_partman插件自动化创建/删除分区(推荐)。- 分区表的
PRIMARY KEY必须包含分区键(如id, event_time)。
五、数据导出与导入 —— 数据迁移与备份的“标准接口”
说明:PostgreSQL 提供标准命令行工具
pg_dump、pg_restore,不依赖 Java 代码。
✅ 标准使用示例(带中文注释)
# 📌 示例1:导出整个数据库(结构+数据)
pg_dump -h localhost -U app_user -d myapp -f myapp_backup.sql
# 📌 示例2:只导出结构(DDL)
pg_dump -h localhost -U app_user -d myapp -s -f myapp_schema.sql
# 📌 示例3:导出单表数据(CSV 格式,便于 Excel 处理)
COPY users (id, username, email, created_at) TO '/tmp/users.csv' WITH CSV HEADER;
# 📌 示例4:从 CSV 导入数据(快速加载)
COPY users (id, username, email, created_at) FROM '/tmp/users.csv' WITH CSV HEADER;
# 📌 示例5:导出为自定义格式(压缩,适合备份)
pg_dump -h localhost -U app_user -d myapp -F c -b -v -f myapp_backup.dump
# 📌 示例6:恢复备份
pg_restore -h localhost -U app_user -d myapp myapp_backup.dump
# 📌 示例7:导出为 JSON(用于 API 或迁移)
SELECT row_to_json(u) FROM users u WHERE status = 'active' LIMIT 10;
✅ 团队规范建议:
- 生产环境备份必须使用
pg_dump -F c(自定义格式),支持并行恢复。- 禁止使用 Java 代码导出 CSV/JSON,性能差、易中断。
- 所有备份文件必须加密存储,定期验证可恢复性。
- 使用
pg_dump+cron+s3cmd实现自动云备份。
六、JSONB 聚合与数组操作 —— 动态数据的“集合引擎”
说明:PostgreSQL 支持对 JSONB 和数组进行聚合、展开、合并、过滤。
✅ 标准使用示例(带中文注释)
-- 📌 示例1:聚合 JSONB 字段(统计不同主题的用户数)
SELECT
metadata->>'theme' AS theme,
COUNT(*) AS user_count
FROM users
WHERE metadata ? 'theme'
GROUP BY metadata->>'theme'
ORDER BY user_count DESC;
-- 📌 示例2:展开 JSONB 数组(将嵌套数组转为行)
-- 用户标签:{"tags": ["admin", "vip", "premium"]}
SELECT
username,
unnest(metadata->'tags'::TEXT[]) AS tag
FROM users
WHERE metadata ? 'tags';
-- ✅ 输出:
-- username | tag
-- alice | admin
-- alice | vip
-- alice | premium
-- 📌 示例3:聚合数组(将多个行合并为一个数组)
SELECT
department_id,
ARRAY_AGG(username) AS member_names
FROM users
WHERE status = 'active'
GROUP BY department_id;
-- ✅ 输出:
-- department_id | member_names
-- 1 | {alice,bob,charlie}
-- 📌 示例4:数组包含查询(查找同时包含 admin 和 vip 的用户)
SELECT *
FROM users
WHERE '{admin,vip}' <@ metadata->'tags'; -- ✅ 数组包含关系
-- 📌 示例5:合并两个 JSONB 对象
SELECT
metadata || '{"last_login": "2025-10-17T10:00:00Z"}'::JSONB AS updated_metadata
FROM users
WHERE id = 1001;
✅ 团队规范建议:
- 所有“多值属性”(标签、权限组、通知设置)统一用
JSONB存储。- 使用
unnest()展开数组,避免 Java 循环解析。- 使用
ARRAY_AGG()聚合,替代 Java 中的List<String>收集。- 所有 JSONB 字段必须建立
GIN索引。
七、全文检索增强 —— 智能搜索的“语义引擎”
说明:PostgreSQL 的全文检索支持多语言、同义词、词干提取、高亮。
✅ 标准使用示例(带中文注释)
-- 📌 示例1:创建中文全文索引(需安装 zhparser 插件)
CREATE EXTENSION IF NOT EXISTS zhparser;
-- 创建中文全文配置
CREATE TEXT SEARCH CONFIGURATION chinese (PARSER = zhparser);
ALTER TEXT SEARCH CONFIGURATION chinese ADD MAPPING FOR word WITH simple;
-- 创建索引
CREATE INDEX idx_articles_content_zh ON articles USING GIN (to_tsvector('chinese', content));
-- 查询(支持中文分词)
SELECT title,
ts_headline('chinese', content, to_tsquery('chinese', 'Spring Boot 教程')) AS snippet
FROM articles
WHERE to_tsvector('chinese', content) @@ to_tsquery('chinese', 'Spring & Boot & 教程');
-- 📌 示例2:使用词典(同义词)
-- 创建同义词文件 /usr/share/postgresql/tsearch_data/synonym.txt
-- spring => java
-- boot => framework
-- 创建词典
CREATE TEXT SEARCH DICTIONARY synonym_dict (
TEMPLATE = synonym,
SYNONYMS = synonym
);
-- 创建配置
CREATE TEXT SEARCH CONFIGURATION synonym_config (PARSER = pg_catalog.simple);
ALTER TEXT SEARCH CONFIGURATION synonym_config ADD MAPPING FOR asciiword WITH synonym_dict, english_stem;
-- 查询
SELECT * FROM articles
WHERE to_tsvector('synonym_config', content) @@ to_tsquery('synonym_config', 'spring & boot');
-- ✅ 会匹配包含 "java framework" 的文章
✅ 团队规范建议:
- 所有搜索功能(商品名、文章标题、用户备注)必须使用全文检索,禁止
LIKE。- 中文搜索必须使用
zhparser或jieba插件。- 使用
ts_headline()高亮匹配词,提升前端体验。- 为全文索引单独设置
tsvector字段,避免每次计算。
八、窗口函数进阶 —— 分析型查询的“超级武器”
说明:超越基础排名,支持移动平均、累计求和、前后行访问。
✅ 标准使用示例(带中文注释)
-- 📌 示例1:移动平均(过去7天平均销售额)
SELECT
order_date,
daily_revenue,
AVG(daily_revenue) OVER (
ORDER BY order_date
ROWS BETWEEN 6 PRECEDING AND CURRENT ROW
) AS avg_7days
FROM (
SELECT
DATE(created_at) AS order_date,
SUM(total_amount) AS daily_revenue
FROM orders
WHERE status = 'paid'
GROUP BY DATE(created_at)
) daily
ORDER BY order_date;
-- 📌 示例2:获取上一行的值(计算增长)
SELECT
user_id,
order_date,
total_amount,
LAG(total_amount, 1) OVER (PARTITION BY user_id ORDER BY order_date) AS prev_amount,
total_amount - LAG(total_amount, 1) OVER (PARTITION BY user_id ORDER BY order_date) AS growth
FROM orders
WHERE status = 'paid'
ORDER BY user_id, order_date;
-- 📌 示例3:获取下一行的值(预测下一个订单)
SELECT
user_id,
order_date,
total_amount,
LEAD(order_date, 1) OVER (PARTITION BY user_id ORDER BY order_date) AS next_order_date
FROM orders
WHERE status = 'paid'
ORDER BY user_id, order_date;
-- 📌 示例4:累计求和(用户终身消费)
SELECT
username,
order_date,
total_amount,
SUM(total_amount) OVER (
PARTITION BY user_id
ORDER BY order_date
ROWS UNBOUNDED PRECEDING
) AS lifetime_spent
FROM users u
JOIN orders o ON u.id = o.user_id
WHERE o.status = 'paid'
ORDER BY u.username, o.order_date;
✅ 团队规范建议:
- 所有“趋势分析”“增长计算”“排行榜”必须用窗口函数。
- 禁止在 Java 中用
for循环计算累计值。ROWS BETWEEN X PRECEDING AND CURRENT ROW是性能关键。- 使用
LAG()/LEAD()实现“上一次操作”“下一次操作”逻辑。
九、系统视图与监控 SQL —— 性能诊断的“望远镜”
说明:PostgreSQL 内置大量系统视图,无需外部工具即可诊断性能瓶颈。
✅ 标准使用示例(带中文注释)
-- 📌 示例1:查看当前所有连接(排查连接池耗尽)
SELECT
pid,
usename,
application_name,
client_addr,
state,
query_start,
now() - query_start AS duration,
query
FROM pg_stat_activity
WHERE state = 'active'
AND usename NOT IN ('postgres', 'rdsadmin')
ORDER BY duration DESC;
-- 📌 示例2:查看最慢的查询(需启用 pg_stat_statements)
SELECT
query,
calls,
total_time,
mean_time,
rows,
100.0 * shared_blks_hit / nullif(shared_blks_hit + shared_blks_read, 0) AS hit_percent
FROM pg_stat_statements
ORDER BY total_time DESC
LIMIT 10;
-- 📌 示例3:查看表大小(排查大表)
SELECT
tablename,
pg_size_pretty(pg_total_relation_size(tablename)) AS total_size
FROM pg_tables
WHERE schemaname = 'public'
ORDER BY pg_total_relation_size(tablename) DESC;
-- 📌 示例4:查看索引使用情况(排查未使用索引)
SELECT
relname AS table_name,
indexrelname AS index_name,
idx_tup_read,
idx_tup_fetch
FROM pg_stat_user_indexes
WHERE idx_tup_read = 0 -- ✅ 从未被使用的索引
ORDER BY relname;
-- 📌 示例5:查看锁等待(排查死锁)
SELECT
blocked_locks.pid AS blocked_pid,
blocking_locks.pid AS blocking_pid,
blocked_activity.query AS blocked_query,
blocking_activity.query AS blocking_query
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;
✅ 团队规范建议:
- 所有生产环境必须开启
pg_stat_statements:CREATE EXTENSION IF NOT EXISTS pg_stat_statements;- 每周运行一次
pg_stat_activity查询,识别长事务。- 每月运行一次
pg_stat_user_indexes,删除无用索引。- 使用
pg_stat_user_tables监控表增长趋势。- 将监控 SQL 集成到 Grafana + Prometheus,实现可视化告警。
十、总结:超越五大分类的 9 大能力,决定你的系统高度
| 能力 | 企业价值 | 推荐使用场景 |
|---|---|---|
| ✅ 序列 | 控制业务 ID 规则,防暴露 | 订单号、发票号、凭证号 |
| ✅ 函数与触发器 | 降低 Java 复杂度,保证一致性 | 自动更新时间戳、状态机转换 |
| ✅ 递归 CTE | 高效查询树形结构 | 组织架构、评论回复、菜单 |
| ✅ 分区表 | 解决大数据量性能瓶颈 | 日志表、行为记录、历史数据 |
| ✅ 导出/导入 | 标准化数据迁移 | 备份、恢复、数据迁移 |
| ✅ JSONB 聚合 | 灵活处理动态属性 | 标签、权限组、配置 |
| ✅ 全文检索 | 替代 LIKE,性能提升百倍 | 商品搜索、文章搜索、用户备注 |
| ✅ 窗口函数进阶 | 替代 Java 循环,精准分析 | 移动平均、增长趋势、预测 |
| ✅ 系统视图 | 实时诊断性能问题 | 慢查询、死锁、索引失效 |
✅ 终极建议:
一个只会写SELECT * FROM users的 Java 开发者,是“数据搬运工”。
一个能熟练使用分区表、递归 CTE、窗口函数、函数触发器的 Java 架构师,是“数据系统设计师”。
📌 下一步行动建议:
- 将本文档作为团队《PostgreSQL 高级实践手册》核心章节。
- 在 GitLab CI 中集成
pg_stat_statements,自动检测慢查询并生成报告。 - 组织一次“PostgreSQL 高级特性实战营”:用递归 CTE 查组织架构、用分区表模拟日志系统。
- 为所有核心表(日志、订单、用户)编写《性能优化方案》:是否需要分区?是否需要函数?是否需要全文索引?
- 制定《数据库监控清单》:每周运行哪些 SQL?谁负责看?
2976

被折叠的 条评论
为什么被折叠?



