慢 SQL 的优化不该从“再加一个索引”开始,而应该先回答三个问题:数据库预计读取多少行、选择了什么访问方式、排序或临时结果发生在哪里。

假设有订单表:

create table orders (
  id bigint primary key,
  user_id bigint not null,
  status varchar(20) not null,
  created_at timestamp not null
);

常见查询是获取某位用户最近完成的订单:

select id, created_at
from orders
where user_id = 42
  and status = 'paid'
order by created_at desc
limit 20;

一个匹配查询形状的联合索引可以是:

create index idx_orders_user_status_created
on orders (user_id, status, created_at desc);

索引先放等值过滤字段,再放排序或范围字段。这样数据库可以快速定位 user_id + status 对应的连续区域,并按索引顺序取前 20 条,减少额外排序。

但索引设计只是猜测,还要用执行计划验证。在 PostgreSQL 中可以运行:

explain (analyze, buffers)
select id, created_at
from orders
where user_id = 42
  and status = 'paid'
order by created_at desc
limit 20;

重点看实际行数与估算行数是否相差悬殊、是否出现全表扫描,以及排序步骤消耗了多少内存和时间。如果估算明显失真,可能需要更新统计信息,而不一定是索引问题。

还要警惕对索引列做函数计算。例如 date(created_at) = ... 可能让普通索引难以使用。通常改写成时间范围更直接:

where created_at >= '2026-02-11 00:00:00'
  and created_at <  '2026-02-12 00:00:00'

优化 SQL 的可靠顺序是:复现慢查询、查看执行计划、提出最小改动、再次测量。没有测量的“优化”,往往只是换一种猜法。