跳到主要内容

查询优化

查询优化的目标是减少扫描数据量、降低排序和关联成本,并让数据库使用合适的索引。优化前应先定位慢查询,再根据执行计划处理瓶颈。

使用 EXPLAIN

EXPLAIN 可以查看查询计划,EXPLAIN ANALYZE 会实际执行 SQL 并输出耗时。

explain analyze
select id, title
from public.todos
where user_id = 'user-1'
order by created_at desc
limit 20;

生产环境使用 EXPLAIN ANALYZE 前要谨慎,因为它会真实执行语句。

创建合适索引

为高频过滤、排序和关联字段创建索引。

create index todos_user_created_idx
on public.todos (user_id, created_at desc);

组合索引的字段顺序很重要。通常把等值过滤字段放前面,把排序字段放后面。

更多索引类型请参考 索引管理

避免全表扫描

常见全表扫描原因包括:

  • 过滤字段没有索引。
  • 对索引字段使用函数或类型转换。
  • 查询条件选择性太低。
  • 统计信息过期。
analyze public.todos;

分页优化

偏移分页在深页时会越来越慢。

select id, title
from public.todos
order by id
limit 20 offset 10000;

大数据量列表建议使用游标分页。

select id, title
from public.todos
where id > 10000
order by id
limit 20;

RLS 性能

RLS 策略会参与每次查询。策略字段应创建索引,并优先使用 (select auth.uid()) 缓存当前用户值。

create index todos_user_id_idx on public.todos(user_id);

create policy "read own rows"
on public.todos
for select to authenticated
using (user_id = (select auth.uid()));

更多 RLS 优化建议请参考 基础权限

优化流程

  1. 记录慢 SQL、参数和执行时间。
  2. 使用 EXPLAIN 查看是否全表扫描、排序或嵌套循环过重。
  3. 补充或调整索引。
  4. 执行 analyze 更新统计信息。
  5. 对比优化前后的执行计划和耗时。

不要只凭经验添加大量索引。索引会增加写入成本和存储成本,应围绕真实查询模式设计。