navicat 不决定是否走 seq scan,真正需优化的是 postgresql 的查询逻辑和索引设计;seq scan 在大表上频繁出现且耗时高,通常因缺失索引、函数导致索引失效、统计信息过期、random_page_cost 设置不当或查询返回数据过多。
navicat 本身不决定是否走 seq scan,它只是执行 postgresql 返回的执行计划——真正要优化的,是 postgresql 的查询逻辑和索引设计。
为什么 Navicat 里看到 Seq Scan 就慢?
Navicat 显示的执行计划来自 EXPLAIN ANALYZE,Seq Scan 出现本身不是错误,但若在大表(比如百万行以上)上频繁出现且耗时高,说明:
- WHERE 条件列没索引,或索引没被用上
- 查询写了函数/类型转换,导致索引失效(如
WHERE to_char(created_at, 'YYYY-MM') = '2026-01') - 统计信息过期,优化器误判全表扫描比索引快(尤其在 SSD 上
random_page_cost值仍为默认 4.0 时) - 查询返回大量数据(如
SELECT *+ 无LIMIT),即使有索引,优化器也可能放弃回表而选顺序扫描
在 Navicat 里快速验证和定位问题
别只看图形化执行计划面板——它常隐藏关键细节。直接在 Navicat 查询窗口运行:
EXPLAIN (ANALYZE, BUFFERS) SELECT * FROM orders WHERE user_id = 12345 AND status = 'pending';
重点关注输出里的这几项:
-
Seq Scan on orders:确认是不是真在扫全表 -
Rows Removed by Filter:如果远大于最终Rows,说明过滤低效,急需索引 -
Buffers: shared hit=xxx read=yyy:read高 = 磁盘 IO 多,缓存未命中 -
Planning Time和Execution Time分开看,排除解析开销干扰
最该优先建的复合索引长什么样?
别急着给每个字段单独建索引。根据 WHERE、ORDER BY、JOIN 条件组合建 B-tree 复合索引,顺序有讲究:
- 等值条件(
=,IN)放最左 - 范围条件(
>,BETWEEN)放中间 - 排序字段(
ORDER BY)放最后(如果需要避免额外Sort节点)
例如这个常见查询:
SELECT * FROM orders WHERE user_id = 12345 AND status IN ('pending', 'processing') ORDER BY created_at DESC LIMIT 20;
对应最优索引是:
CREATE INDEX idx_orders_user_status_created ON orders (user_id, status, created_at DESC);
注意:status IN 是等值类操作,可进索引;created_at DESC 匹配 ORDER BY ... DESC,能消除排序节点。
容易被忽略但影响巨大的两件事
一是 ANALYZE 没跑——表数据大改后(如批量导入、删了 30% 行),统计信息不准,优化器就“瞎猜”。在 Navicat 里右键表 → “分析表” 或执行 ANALYZE orders;。
二是 Navicat 默认关闭了 track_io_timing,导致 BUFFERS 输出里看不到真实磁盘读写。需先连上服务器执行:
ALTER SYSTEM SET track_io_timing = on;
再重启 PostgreSQL(或至少 reload)。否则你永远不知道 Seq Scan 慢,到底是 CPU 卡住,还是真在疯狂读盘。











