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,否则扫描全部匹配行 |
I have a dream : Sandy beach B-J-N.
浙公网安备 33010602011771号