好好生活
  平平淡淡每一天

编辑

GaussDB 大表数据存在性查询

一、查询执行计划 —— 扫描方式优先级

GaussDB 查询优化器扫描方式优先级(从高到低):

排名 扫描类型 说明
1 Index Only Scan(仅索引扫描) 所有需要的列都在索引中,无需回表
2 Index Scan(索引扫描) 通过索引定位数据,再回表获取完整行
3 Bitmap Index Scan + Bitmap Heap Scan(位图扫描) 先构建位图,再批量获取数据页
4 Sequential Scan(顺序扫描/全表扫描) 逐行扫描整个表

Index Scan 排第 2 位。

优化器基于 成本估算(COST) 决定,非固定顺序。通过 EXPLAIN ANALYZE 查看实际执行计划。


二、大表索引创建风险与数据量阈值

经验参考值

数据量 风险等级 建议
< 1000 万行 正常创建
1000 万 ~ 1 亿行 低峰期操作,关注磁盘和内存
1 亿 ~ 10 亿行 必须使用 CONCURRENTLY,提前评估空间
> 10 亿行 极高 分批、分区索引或使用在线工具

主要风险

  • 磁盘空间不足:创建过程峰值占用为最终索引大小的 2~3 倍
  • 锁超时失败:并发长事务占用表锁导致冲突
  • 内存不足(OOM)maintenance_work_mem 偏小
  • WAL 日志暴增:超大表创建索引产生大量日志

关键参数

SET maintenance_work_mem = '2GB';
SET lock_timeout = '300s';

最佳实践

-- 使用 CONCURRENTLY 避免锁表
CREATE INDEX CONCURRENTLY idx_name ON table_name(column_name);

-- 分区表使用 LOCAL 索引
CREATE INDEX idx_part ON partition_table(column_name) LOCAL;

三、限制查询只返回单条记录(LIMIT 用法)

-- 最常用写法
SELECT * FROM table_name WHERE condition LIMIT 1;

-- 标准 SQL 语法
SELECT * FROM table_name WHERE condition FETCH FIRST 1 ROWS ONLY;

-- 随机 1 条
SELECT * FROM table_name ORDER BY RANDOM() LIMIT 1;

-- 最大/最小的 1 条
SELECT * FROM table_name ORDER BY column_name DESC LIMIT 1;
SELECT * FROM table_name ORDER BY column_name ASC  LIMIT 1;

四、数据存在性判断 —— 存在返回 1,不存在返回 0

推荐写法:CASE + EXISTS

SELECT CASE WHEN EXISTS (
    SELECT 1 FROM table_name WHERE column_name = 'value'
) THEN 1 ELSE 0 END;

其他写法

-- COALESCE + LIMIT
SELECT COALESCE((SELECT 1 FROM table_name WHERE column_name = 'value' LIMIT 1), 0);

-- COUNT + LIMIT
SELECT COUNT(*) FROM (
    SELECT 1 FROM table_name WHERE column_name = 'value' LIMIT 1
) t;
写法 性能 说明
CASE WHEN EXISTS 最优 找到即停,语义最清晰
COALESCE + LIMIT 较优 同样找到即停
COUNT(*) 注意 务必加 LIMIT 1,否则扫描全部匹配行
posted @ 2026-05-21 15:24  踏步  阅读(16)  评论(0)    收藏  举报