人大金仓慢 SQL 根治方法论:问题定位 - 分析 - 优化全流程

📝 摘要

本文基于人大金仓 V9.7.0 生产环境实战经验,整理出一套完整的慢 SQL 根治方法论。从问题定位 (慢查询日志、实时监控、历史统计、锁等待分析)到深度分析 (执行计划解读、异常识别、统计信息排查),再到落地优化(索引、SQL 重构、参数调优、表结构优化),全程提供可直接复制的 SQL 和配置。特别针对金仓与 PostgreSQL 的核心差异点进行了重点说明,解决了政务信创项目中 90% 以上的慢 SQL 问题。

政务选金仓,金融选达梦;MySQL 迁移选金仓,Oracle 迁移选达梦专注 SpringBoot3 + 人大金仓 + 达梦信创实战,关注不迷路

📚 目录

  1. [🔍 问题定位:3 分钟找到所有慢 SQL](#🔍 问题定位:3 分钟找到所有慢 SQL)
    • [📜 1.1 慢查询日志开启(生产必配)](#📜 1.1 慢查询日志开启(生产必配))
    • [⚡ 1.2 实时慢 SQL 查询(紧急排查)](#⚡ 1.2 实时慢 SQL 查询(紧急排查))
    • [📊 1.3 历史慢 SQL 统计(sys_stat_statements)](#📊 1.3 历史慢 SQL 统计(sys_stat_statements))
    • [🔧 1.4 auto_explain 插件(自动记录执行计划)](#🔧 1.4 auto_explain 插件(自动记录执行计划))
    • [🔒 1.5 锁等待与阻塞分析](#🔒 1.5 锁等待与阻塞分析)
  2. [🔬 问题分析:读懂金仓执行计划的核心要点](#🔬 问题分析:读懂金仓执行计划的核心要点)
    • [📖 2.1 EXPLAIN 命令详解与最佳实践](#📖 2.1 EXPLAIN 命令详解与最佳实践)
    • [🎯 2.2 执行计划关键指标与算子解读](#🎯 2.2 执行计划关键指标与算子解读)
    • [⚠️ 2.3 常见异常执行计划识别与诊断](#⚠️ 2.3 常见异常执行计划识别与诊断)
    • [🔄 2.4 金仓与 PostgreSQL 执行计划核心差异](#🔄 2.4 金仓与 PostgreSQL 执行计划核心差异)
    • [📈 2.5 统计信息异常排查与修复](#📈 2.5 统计信息异常排查与修复)
  3. [💡 问题优化:从 SQL 到参数的全维度调优](#💡 问题优化:从 SQL 到参数的全维度调优)
    • [🗂️ 3.1 索引优化:性价比最高的优化手段](#🗂️ 3.1 索引优化:性价比最高的优化手段)
    • [✍️ 3.2 SQL 语句重构:从根本上解决性能问题](#✍️ 3.2 SQL 语句重构:从根本上解决性能问题)
    • [💪 3.3 HINT 提示:强制优化器执行正确计划](#💪 3.3 HINT 提示:强制优化器执行正确计划)
    • [⚙️ 3.4 关键参数调优:挖掘数据库性能潜力](#⚙️ 3.4 关键参数调优:挖掘数据库性能潜力)
    • [🏗️ 3.5 表结构优化:从设计层面避免慢 SQL](#🏗️ 3.5 表结构优化:从设计层面避免慢 SQL)
  4. [🚫 避坑要点:金仓慢 SQL 优化的 12 个致命陷阱](#🚫 避坑要点:金仓慢 SQL 优化的 12 个致命陷阱)
  5. [✅ 生产环境验证与监控体系搭建](#✅ 生产环境验证与监控体系搭建)
  6. [🎁 总结与专栏推荐](#🎁 总结与专栏推荐)

🔍 1. 问题定位:3 分钟找到所有慢 SQL

调优的第一步永远是精准定位,而不是上来就乱改参数。金仓 V9 提供了 5 种定位慢 SQL 的方式,覆盖实时、历史、全量、锁等待等所有场景。

📜 1.1 慢查询日志开启(生产必配)

这是最基础也是最有效的定位手段,建议所有生产环境在上线前就配置好。

💻 可直接复制的完整配置(kingbase.conf)

复制代码
# 开启日志收集器(必须)
logging_collector = on
# 日志输出格式(CSV便于后续用Excel或脚本分析)
log_destination = 'csvlog'
# 日志目录(相对data目录,建议单独挂载磁盘)
log_directory = 'pg_log'
# 日志文件名格式
log_filename = 'kingbase-slow-%Y-%m-%d_%H.log'
# 日志轮转:每小时一个文件
log_rotation_age = 60
# 日志轮转:单个文件最大1GB
log_rotation_size = 1GB
# 自动截断旧日志(避免磁盘占满)
log_truncate_on_rotation = on
# 保留最近7天的日志
log_retention_period = '7d'

# 慢查询核心配置:记录执行超过100ms的SQL
# 注意:生产环境不要设置为0,会产生海量日志
log_min_duration_statement = 100
# 记录所有DDL语句
log_statement = 'ddl'
# 记录锁等待超过1秒的信息
log_lock_waits = on
log_min_messages = warning
# 记录检查点信息(用于IO性能分析)
log_checkpoints = on
# 记录连接和断开信息
log_connections = on
log_disconnections = on
# 日志前缀:包含时间、进程ID、用户、数据库、客户端IP、应用名称
log_line_prefix = '%m %p %u %d %r %a '

🔧 配置生效与验证

复制代码
# 重载配置(不需要重启,推荐)
sys_ctl reload -D /data/kingbase
# 验证配置是否生效
ksql -Usystem -d your_db -c "show log_min_duration_statement;"
# 查看日志文件
tail -f /data/kingbase/pg_log/kingbase-slow-$(date +%Y-%m-%d_%H).log

⚡ 1.2 实时慢 SQL 查询(紧急排查)

当系统突然卡顿,CPU 或 IO 飙升时,需要立即查看当前正在执行的慢 SQL:

sql 复制代码
-- 查看TOP 10耗时最长的活跃SQL(最常用)
SELECT 
    pid,
    usename,
    datname,
    application_name,
    client_addr,
    state,
    query_start,
    now() - query_start AS duration,
    query
FROM sys_stat_activity
WHERE state = 'active'
  AND pid <> sys_backend_pid()
ORDER BY duration DESC
LIMIT 10;

-- 查看长事务(idle in transaction状态,最容易导致锁阻塞)
SELECT 
    pid,
    usename,
    datname,
    client_addr,
    query_start,
    now() - query_start AS duration,
    query
FROM sys_stat_activity
WHERE state = 'idle in transaction'
ORDER BY duration DESC;

-- 查看等待事件(金仓特有,非常重要)
SELECT 
    pid,
    usename,
    datname,
    wait_event_type,
    wait_event,
    query
FROM sys_stat_activity
WHERE wait_event IS NOT NULL
  AND pid <> sys_backend_pid()
ORDER BY query_start DESC;

-- 终止指定慢SQL进程(安全终止)
SELECT sys_terminate_backend(12345); -- 替换为实际pid
-- 强制终止(慎用,可能导致事务回滚)
SELECT sys_cancel_backend(12345);

📊 1.3 历史慢 SQL 统计(sys_stat_statements)

这是金仓最强大的性能分析插件,能统计所有 SQL 的执行次数、总耗时、平均耗时、IO 消耗等指标。

🔧 插件安装与配置

复制代码
# kingbase.conf添加(注意:必须重启数据库)
shared_preload_libraries = 'sys_stat_statements'
# 跟踪所有SQL,包括存储过程内部的SQL
sys_stat_statements.track = all
# 最多记录10000条SQL
sys_stat_statements.max = 10000
# 跟踪执行计划
sys_stat_statements.track_planning = on

💻 重启后创建扩展

复制代码
CREATE EXTENSION IF NOT EXISTS sys_stat_statements;

📈 TOP 10 慢 SQL 查询(按总耗时排序)

复制代码
SELECT 
    queryid,
    query,
    calls,
    total_time,
    mean_time,
    max_time,
    min_time,
    rows,
    shared_blks_hit,
    shared_blks_read,
    shared_blks_dirtied,
    temp_files,
    temp_bytes
FROM sys_stat_statements
ORDER BY total_time DESC
LIMIT 10;

-- TOP 10按平均耗时排序
SELECT * FROM sys_stat_statements ORDER BY mean_time DESC LIMIT 10;

-- TOP 10按IO消耗排序
SELECT * FROM sys_stat_statements ORDER BY shared_blks_read DESC LIMIT 10;

-- 重置统计信息(优化前后对比用)
SELECT sys_stat_statements_reset();

🔧 1.4 auto_explain 插件(自动记录执行计划)

对于偶尔出现的慢 SQL,手动抓执行计划很困难。auto_explain 可以自动将慢 SQL 的执行计划写入日志。

💻 配置

复制代码
shared_preload_libraries = 'sys_stat_statements,auto_explain'
# 记录执行超过100ms的SQL的执行计划
auto_explain.log_min_duration = 100
# 真实执行并显示实际运行时间
auto_explain.log_analyze = on
# 显示缓冲区使用情况
auto_explain.log_buffers = on
# 显示详细信息
auto_explain.log_verbose = on
# 显示触发器执行时间
auto_explain.log_triggers = on
# 记录嵌套语句的执行计划
auto_explain.log_nested_statements = on

🔒 1.5 锁等待与阻塞分析

很多时候 SQL 慢不是因为执行慢,而是因为被其他事务阻塞了。金仓提供了专门的视图来查看锁信息:

复制代码
-- 查看当前所有锁
SELECT 
    pid,
    usename,
    datname,
    relation::regclass AS table_name,
    locktype,
    mode,
    granted
FROM sys_locks
WHERE relation IS NOT NULL
ORDER BY pid;

-- 查看阻塞关系(谁阻塞了谁)
SELECT 
    blocked.pid AS blocked_pid,
    blocked.usename AS blocked_user,
    blocked.query AS blocked_query,
    blocking.pid AS blocking_pid,
    blocking.usename AS blocking_user,
    blocking.query AS blocking_query,
    now() - blocked.query_start AS blocked_duration
FROM sys_stat_activity blocked
JOIN sys_locks bl ON blocked.pid = bl.pid
JOIN sys_locks bk ON bl.relation = bk.relation AND bl.locktype = bk.locktype
JOIN sys_stat_activity blocking ON bk.pid = blocking.pid
WHERE NOT bl.granted AND bk.granted;

🔬 2. 问题分析:读懂金仓执行计划的核心要点

定位到慢 SQL 后,下一步就是分析执行计划。金仓 V9 的执行计划语法与 PostgreSQL 兼容,但在代价模型、算子行为和统计信息处理上有明显差异。

📖 2.1 EXPLAIN 命令详解与最佳实践

💻 最常用的完整命令

复制代码
-- 真实执行并显示详细执行计划(推荐,90%的场景用这个)
EXPLAIN (ANALYZE, BUFFERS, VERBOSE, COSTS)
SELECT * FROM t_orders WHERE order_date > '2026-01-01';

-- 对于DML语句,不想影响数据可以用事务包裹
BEGIN;
EXPLAIN (ANALYZE, BUFFERS) UPDATE t_orders SET status = 1 WHERE id = 123;
ROLLBACK;

-- 只生成执行计划,不真实执行(用于快速查看)
EXPLAIN SELECT * FROM t_orders WHERE order_date > '2026-01-01';

📋 EXPLAIN 选项对比表

选项 默认值 功能说明 使用场景
ANALYZE false 真实执行 SQL 并显示实际运行时间和行数 ✅ 必须开启,否则只能看预估
BUFFERS false 显示缓冲区使用情况(必须配合 ANALYZE) 📊 分析 IO 性能问题时必须开启
VERBOSE false 显示详细信息,如字段名、表别名、函数调用 🔍 复杂查询时开启
COSTS true 显示执行计划的预估成本 📈 对比不同执行计划时有用
TIMING true 显示每个节点的实际执行时间 ⏱️ 定位哪个节点最慢
SUMMARY true 显示执行计划的总耗时和统计信息 ✅ 开启
FORMAT text 输出格式:text、json、xml、yaml 🤖 自动化分析时用 json

🎯 2.2 执行计划关键指标与算子解读

拿到执行计划后,从下往上读,重点关注以下几个指标:

📊 核心指标

  • cost:优化器预估的成本,由启动成本和总成本组成(如 0.00..100.00)
  • rows:优化器预估的返回行数
  • width:预估的每行平均字节数
  • actual time:实际执行时间(单位:毫秒)
  • actual rows:实际返回行数
  • loops:该节点执行的次数

📋 常见算子解读

算子 中文名称 性能评价 说明
Seq Scan 顺序扫描 ❌ 差 全表扫描,数据量大时性能极差
Index Scan 索引扫描 ✅ 好 通过索引查找,然后回表获取数据
Index Only Scan 仅索引扫描 ⭐ 极好 不需要回表,直接从索引获取所有数据
Bitmap Index Scan 位图索引扫描 ✅ 较好 先扫描索引生成位图,再根据位图访问表
Bitmap Heap Scan 位图堆扫描 ✅ 较好 配合 Bitmap Index Scan 使用
Nested Loop 嵌套循环连接 ✅ 小表好 适合小表驱动大表,内表有索引
Hash Join 哈希连接 ✅ 大表好 适合大表之间的等值连接
Merge Join 归并连接 ✅ 排序好 适合两个已经排序的表连接
Sort 排序 ❌ 差 内存不足时会溢出到磁盘
HashAggregate 哈希聚合 ✅ 好 用于 GROUP BY 和聚合函数
GroupAggregate 分组聚合 ❌ 差 数据已经排序时使用
Limit 限制 ✅ 好 只返回前 N 行

🏷️ 金仓特有算子

  • KSHJoin:金仓优化的哈希连接算子,比 PostgreSQL 的 Hash Join 在大数据量下性能更好
  • KSort:金仓优化的排序算子,支持并行排序
  • KBitmapHeapScan:金仓优化的位图堆扫描算子

⚠️ 2.3 常见异常执行计划识别与诊断表格

异常现象 问题原因 优化方向
大表 Seq Scan(行数 > 10 万) 缺失索引或索引失效 创建合适的索引
Nested Loop 内表是大表 连接顺序错误 调整连接顺序或使用 Hash Join
Hash Join 出现大量 Disk work_mem 不足 调大 work_mem 参数
预估行数与实际行数相差 10 倍以上 统计信息过期 手动收集统计信息
出现 Materialize 节点 子查询未优化 重构 SQL 为 JOIN
Sort 节点出现 Disk: work_mem 不足 调大 work_mem 或减少排序数据量
出现 Nested Loop+Seq Scan 内表没有索引 为内表连接字段创建索引
出现多个 Bitmap Heap Scan 多个索引组合查询 创建联合索引

🔄 2.4 金仓与 PostgreSQL 执行计划核心差异

这是很多人踩坑的地方!金仓虽然基于 PostgreSQL 内核,但在代价模型和算子行为上有明显差异:

维度 PostgreSQL 14 人大金仓 V9.7 影响
Seq Scan 启动代价 0.0 100.0 金仓更倾向于使用索引扫描
索引扫描选择率 基于直方图插值计算 固定经验值 0.05 金仓对索引的选择更保守
Hash Join 实现 动态批处理 + 内存自适应 强制依赖预设哈希桶数 金仓 Hash Join 对 work_mem 更敏感
统计信息更新频率 自动触发(默认 20% 数据变更) 相对保守(默认 50% 数据变更) 金仓更容易出现统计信息过期
并行查询支持 完善 有限支持 金仓并行查询性能不如 PostgreSQL
子查询优化 较好 一般 金仓子查询更容易被优化成嵌套循环

📈 2.5 统计信息异常排查与修复

执行计划不准确 90% 是因为统计信息过期或不准确。金仓提供了多种方式来查看和修复统计信息:

复制代码
-- 查看表的统计信息
SELECT 
    relname,
    reltuples,
    relpages,
    last_analyze,
    last_autoanalyze
FROM sys_stat_user_tables
WHERE relname = 't_orders';

-- 查看列的统计信息
SELECT 
    attname,
    n_distinct,
    most_common_vals,
    most_common_freqs,
    histogram_bounds
FROM sys_stats
WHERE tablename = 't_orders' AND attname = 'order_date';

-- 收集单表统计信息
ANALYZE t_orders;

-- 收集单表指定列的统计信息
ANALYZE t_orders(order_date, customer_id);

-- 收集全库统计信息
ANALYZE;

-- 收集详细统计信息(适合数据分布不均匀的表)
ANALYZE VERBOSE t_orders;

-- 调整自动统计信息触发阈值(大表建议调小)
ALTER TABLE t_orders SET (autovacuum_analyze_scale_factor = 0.02);
ALTER TABLE t_orders SET (autovacuum_analyze_threshold = 5000);

💡 3. 问题优化:从 SQL 到参数的全维度调优

🗂️ 3.1 索引优化:性价比最高的优化手段

索引是数据库性能的第一道防线,金仓 V9 支持多种索引类型。

3.1.1 覆盖索引避免回表是索引优化的终极目标:

复制代码
-- 普通索引(需要回表)
CREATE INDEX idx_orders_date ON t_orders(order_date);

-- 覆盖索引(不需要回表,性能提升3-10倍)
CREATE INDEX idx_orders_date_cover ON t_orders(order_date) INCLUDE (id, customer_id, total_amount, status);

-- 验证是否使用了覆盖索引(执行计划中出现Index Only Scan)
EXPLAIN (ANALYZE) SELECT id, customer_id, total_amount FROM t_orders WHERE order_date > '2026-01-01';

3.1.2 联合索引 遵循最左前缀原则,过滤性高的字段放前面:

复制代码
-- 好:customer_id过滤性高,order_date次之
CREATE INDEX idx_orders_customer_date ON t_orders(customer_id, order_date);

-- 差:order_date过滤性低,放在前面
CREATE INDEX idx_orders_date_customer ON t_orders(order_date, customer_id);

-- 联合覆盖索引
CREATE INDEX idx_orders_customer_date_cover ON t_orders(customer_id, order_date) INCLUDE (total_amount, status);

3.1.3 函数索引当必须在索引列上使用函数时,创建函数索引:

复制代码
-- 错误:索引失效
SELECT * FROM t_orders WHERE UPPER(customer_name) = 'ZHANGSAN';

-- 正确:创建函数索引
CREATE INDEX idx_orders_customer_name_upper ON t_orders(UPPER(customer_name));

3.1.4 JSONB 索引金仓 V9 对 JSONB 类型支持很好:

复制代码
-- GIN索引(适合包含查询)
CREATE INDEX idx_orders_extra_gin ON t_orders USING GIN(extra);

-- 特定JSON路径索引(性能更好)
CREATE INDEX idx_orders_extra_status ON t_orders((extra->>'status'));
CREATE INDEX idx_orders_extra_amount ON t_orders(((extra->>'amount')::NUMERIC));

3.1.5 部分索引只对表中部分数据创建索引,节省空间并提高性能:

复制代码
-- 只对未完成的订单创建索引
CREATE INDEX idx_orders_status_pending ON t_orders(order_date) WHERE status = 0;

✍️ 3.2 SQL 语句重构:从根本上解决性能问题

3.2.1 分页查询优化金仓 V9 中 OFFSET 越大,性能越差:

复制代码
-- 慢:OFFSET 100000(需要扫描前100000行)
SELECT * FROM t_orders ORDER BY id LIMIT 10 OFFSET 100000;

-- 快:游标式分页(Keyset Pagination)
SELECT * FROM t_orders WHERE id > 100000 ORDER BY id LIMIT 10;

-- 多字段排序的游标式分页
SELECT * FROM t_orders 
WHERE (order_date, id) > ('2026-01-01', 100000) 
ORDER BY order_date DESC, id DESC 
LIMIT 10;

3.2.2 子查询优化尽量将子查询改为 JOIN:

复制代码
-- 慢:IN子查询(金仓优化器处理不好)
SELECT * FROM t_orders 
WHERE customer_id IN (SELECT id FROM t_customers WHERE region = 'Beijing');

-- 快:JOIN
SELECT o.* FROM t_orders o
JOIN t_customers c ON o.customer_id = c.id
WHERE c.region = 'Beijing';

-- 慢:EXISTS子查询
SELECT * FROM t_orders o
WHERE EXISTS (SELECT 1 FROM t_order_items oi WHERE oi.order_id = o.id AND oi.price > 1000);

-- 快:JOIN+DISTINCT
SELECT DISTINCT o.* FROM t_orders o
JOIN t_order_items oi ON o.id = oi.order_id
WHERE oi.price > 1000;

3.2.3 COUNT (*) 优化金仓中 COUNT (*) 会扫描全表,大数据量下很慢:

复制代码
-- 慢:精确计数(1000万行需要几秒)
SELECT COUNT(*) FROM t_orders;

-- 快:近似计数(误差<5%,毫秒级)
SELECT reltuples::BIGINT FROM sys_class WHERE relname = 't_orders';

-- 业务优化:单独维护计数表
CREATE TABLE t_counter (
    table_name VARCHAR(50) PRIMARY KEY,
    count BIGINT NOT NULL DEFAULT 0
);

-- 插入时更新计数
INSERT INTO t_orders (...) VALUES (...);
UPDATE t_counter SET count = count + 1 WHERE table_name = 't_orders';

3.2.4 OR 条件优化OR 连接的条件会导致无法使用索引,改用 UNION ALL:

复制代码
-- 慢:OR条件
SELECT * FROM t_orders WHERE customer_id = 123 OR order_date > '2026-01-01';

-- 快:UNION ALL
SELECT * FROM t_orders WHERE customer_id = 123
UNION ALL
SELECT * FROM t_orders WHERE order_date > '2026-01-01' AND customer_id <> 123;

💪 3.3 HINT 提示:强制优化器执行正确计划

当优化器选择了错误的执行计划时,可以使用 HINT 强制指定。金仓 V9 支持与 Oracle 兼容的 HINT 语法:

复制代码
-- 强制使用指定索引
SELECT /*+ IndexScan(t_orders idx_orders_date) */ * 
FROM t_orders WHERE order_date > '2026-01-01';

-- 强制全表扫描
SELECT /*+ SeqScan(t_orders) */ * 
FROM t_orders WHERE order_date > '2026-01-01';

-- 强制使用哈希连接
SELECT /*+ HashJoin(o c) */ * 
FROM t_orders o JOIN t_customers c ON o.customer_id = c.id;

-- 强制使用嵌套循环连接
SELECT /*+ NestLoop(o c) */ * 
FROM t_orders o JOIN t_customers c ON o.customer_id = c.id;

-- 指定连接顺序
SELECT /*+ Leading((c o)) */ * 
FROM t_orders o JOIN t_customers c ON o.customer_id = c.id;

-- 开启并行查询
SELECT /*+ Parallel(t_orders 4) */ * 
FROM t_orders WHERE order_date > '2026-01-01';

⚙️ 3.4 关键参数调优:挖掘数据库性能潜力

💻 内存相关参数(根据服务器配置调整)

复制代码
# 共享缓冲区(建议设置为物理内存的25%-50%)
# 16G内存:4GB
# 32G内存:8GB
# 64G内存:16GB
shared_buffers = 8GB

# 工作内存(每个连接的排序和哈希操作内存)
# 并发连接数少:64MB-256MB
# 并发连接数多:16MB-32MB
work_mem = 64MB

# 维护工作内存(索引创建、VACUUM等操作)
# 建议设置为物理内存的5%-10%
maintenance_work_mem = 2GB

# 有效缓存大小(告诉优化器系统有多少内存可用)
# 建议设置为物理内存的75%
effective_cache_size = 24GB

# 共享内存段大小
max_prepared_transactions = 100

💻 查询优化器参数

复制代码
# 关闭嵌套循环(当大表连接时)
# enable_nestloop = off

# 关闭归并连接(大多数场景下Hash Join更好)
# enable_mergejoin = off

# 开启并行查询
max_parallel_workers_per_gather = 4
max_parallel_workers = 8
parallel_setup_cost = 1000
parallel_tuple_cost = 0.1

# 调整代价模型参数
random_page_cost = 1.1  # SSD磁盘建议设置为1.1
seq_page_cost = 1.0
cpu_tuple_cost = 0.01
cpu_index_tuple_cost = 0.005
cpu_operator_cost = 0.0025

💻 自动清理参数

复制代码
# 调整自动清理阈值
autovacuum_vacuum_scale_factor = 0.05
autovacuum_analyze_scale_factor = 0.02
autovacuum_vacuum_threshold = 5000
autovacuum_analyze_threshold = 5000

# 增加自动清理工作进程数
autovacuum_max_workers = 4

# 调整自动清理的IO限制
autovacuum_vacuum_cost_delay = 2ms
autovacuum_vacuum_cost_limit = 2000

🏗️ 3.5 表结构优化:从设计层面避免慢 SQL

3.5.1 表分区对于大表(>1000 万行),建议使用分区表:

复制代码
-- 创建按时间分区的订单表
CREATE TABLE t_orders (
    id BIGINT PRIMARY KEY,
    customer_id BIGINT NOT NULL,
    order_date DATE NOT NULL,
    total_amount NUMERIC(10,2) NOT NULL,
    status INT NOT NULL DEFAULT 0
) PARTITION BY RANGE (order_date);

-- 创建分区
CREATE TABLE t_orders_202601 PARTITION OF t_orders
FOR VALUES FROM ('2026-01-01') TO ('2026-02-01');

CREATE TABLE t_orders_202602 PARTITION OF t_orders
FOR VALUES FROM ('2026-02-01') TO ('2026-03-01');

3.5.2 字段类型优化

  • ✅ 使用最小的数据类型:能用 INT 就不用 BIGINT,能用 VARCHAR (50) 就不用 VARCHAR (255)
  • ✅ 避免使用 TEXT 类型存储短字符串
  • ✅ 日期时间使用 DATE 或 TIMESTAMP,不要用 VARCHAR
  • ✅ 金额使用 NUMERIC 类型,不要用 FLOAT 或 DOUBLE

3.5.3 避免大字段将大字段(如 TEXT、BLOB)单独拆分到子表中:

复制代码
-- 主表
CREATE TABLE t_orders (
    id BIGINT PRIMARY KEY,
    customer_id BIGINT NOT NULL,
    order_date DATE NOT NULL,
    total_amount NUMERIC(10,2) NOT NULL
);

-- 子表存储大字段
CREATE TABLE t_orders_detail (
    order_id BIGINT PRIMARY KEY REFERENCES t_orders(id),
    remark TEXT,
    attachment BYTEA
);

🚫 4. 避坑要点:金仓慢 SQL 优化的 12 个致命陷阱

  1. 不要盲目创建索引:索引会降低写入性能,单表索引数建议不超过 5 个
  2. 不要忽略统计信息:金仓的自动统计信息更新比较保守,大表变更后要手动 ANALYZE
  3. 不要直接照搬 PostgreSQL 的优化经验:两者在代价模型和算子行为上有明显差异
  4. 不要在索引列上使用函数或表达式:会导致索引失效,必须使用时创建函数索引
  5. ❌ ** 不要使用 SELECT ***:只查询需要的字段,尽量使用覆盖索引
  6. 不要使用大 OFFSET 分页:超过 10000 行必须使用游标式分页
  7. 不要在事务中执行复杂查询:会导致长事务和锁阻塞
  8. 不要忽略 work_mem 参数:太小会导致哈希连接和排序操作溢出到磁盘
  9. 不要使用 OR 连接多个条件:会导致无法使用索引,改用 UNION ALL
  10. 不要忘记定期 VACUUM:金仓的 MVCC 机制会产生死元组,不清理会导致表膨胀
  11. 不要使用子查询:金仓优化器对子查询的处理不如 JOIN 好
  12. 不要在生产环境使用 EXPLAIN ANALYZE 执行 DML 语句:会真实修改数据

✅ 5. 生产环境验证与监控体系搭建

📊 优化前后对比验证

复制代码
-- 优化前记录统计信息
SELECT sys_stat_statements_reset();

-- 执行优化后的SQL
SELECT ...;

-- 查看优化后的性能指标
SELECT query, calls, total_time, mean_time, rows FROM sys_stat_statements WHERE query LIKE '%your_sql%';

📡 慢 SQL 监控体系搭建

  1. 📜 配置慢查询日志,每天自动分析并生成报告
  2. 📊 使用 Prometheus+Grafana 监控数据库性能指标
  3. 🚨 设置告警阈值,当慢 SQL 数量超过阈值时自动告警
  4. 🔄 定期(每周)审查慢 SQL 日志,持续优化

🎁 6. 总结与专栏推荐

人大金仓慢 SQL 优化是一个系统性工程,遵循先定位、再分析、后优化的原则。本文提供的方法已经在多个政务信创项目中验证有效,能够解决 90% 以上的慢 SQL 问题。

📌 核心要点回顾

  • ✅ 生产环境必须开启慢查询日志和 sys_stat_statements 插件
  • ✅ 分析执行计划重点关注扫描类型、连接方式和行数预估
  • ✅ 索引优化是性价比最高的手段,优先使用覆盖索引
  • ✅ 金仓与 PostgreSQL 的差异点是最容易踩坑的地方
  • ✅ 优化后一定要进行验证和监控

如果这篇文章对你有帮助,欢迎点赞、收藏、关注三连!

相关推荐
吃饱了得干活2 分钟前
JVM垃圾回收:从新生代到ZGC,从理论到调优
java·jvm·后端
Conan在掘金10 分钟前
鸿蒙报错速查:arkts-no-func-expressions 禁用 function 表达式,用了就炸,根因 + 真解法
后端
geovindu10 分钟前
python: Breadth First Search Algorithm and Depth First Search Algorithm
开发语言·后端·python·算法·搜索算法
笨笨饿23 分钟前
#102_Codex无在VSCold无法打开
java·c语言·数据库·笔记
向夏威夷 梦断明暄29 分钟前
基于Tez引擎的 Hive SQL 性能优化
hive·sql·性能优化
程序员清风30 分钟前
AI不是万能的,大家要专注实践!
java·后端·面试
向夏威夷 梦断明暄30 分钟前
从架构特点到功能缺陷,重新认识分析型分布式数据库
数据库·分布式·架构
Mico1834 分钟前
MySQL 8.0.35 主从延迟模拟与解决
mysql
刘沅44 分钟前
Redis的哨兵机制
后端·面试
不知疲倦的仄仄1 小时前
MySQL/Read View快照/MVCC/串行化
java·数据库·mysql