返回文章列表
数据库PostgreSQL性能

PostgreSQL 索引策略实战

D
Dev Notes
9 min read

索引是数据库性能的关键,但滥用同样有代价。深入讲解 B-Tree、GIN、BRIN 等索引类型的选择与优化。

PostgreSQL 的索引是双刃剑:用好了查询飞速,用错了写入缓慢、存储膨胀。

索引类型选择

B-Tree(默认)

适用于等值和范围查询:

-- 单列索引

CREATE INDEX idx_users_email ON users(email);

-- 复合索引(注意列顺序!)

CREATE INDEX idx_posts_user_date ON posts(user_id, created_at DESC);

复合索引遵循最左前缀原则(user_id, created_at) 可以支持 WHERE user_id = ??WHERE user_id = ?? AND created_at > ??,但不支持单独的 WHERE created_at > ??

GIN(Generalized Inverted Index)

适用于全文搜索、数组、JSONB:

-- 全文搜索

CREATE INDEX idx_posts_fts ON posts USING GIN(

to_tsvector('chinese', title || ' ' || content)

);

-- JSONB 查询

CREATE INDEX idx_metadata ON products USING GIN(metadata);

BRIN(Block Range Index)

适用于有自然顺序的大表(如时间序列):

-- 日志表按时间范围查询

CREATE INDEX idx_logs_created ON logs USING BRIN(created_at);

BRIN 存储极小,特别适合时序数据。

索引优化技巧

部分索引(Partial Index)

只索引满足条件的行:

-- 只索引未读通知

CREATE INDEX idx_notifications_unread

ON notifications(user_id, created_at)

WHERE read = false;

-- 只索引活跃用户

CREATE INDEX idx_active_users ON users(email)

WHERE deleted_at IS NULL;

部分索引更小,查询更快。

覆盖索引(Covering Index)

-- INCLUDE 列避免回表

CREATE INDEX idx_posts_covering

ON posts(user_id, created_at DESC)

INCLUDE (title, excerpt);

诊断工具

-- 查看执行计划

EXPLAIN (ANALYZE, BUFFERS)

SELECT * FROM posts WHERE user_id = 1 ORDER BY created_at DESC LIMIT 10;

-- 查看索引使用情况

SELECT schemaname, tablename, indexname, idx_scan, idx_tup_read

FROM pg_stat_user_indexes

ORDER BY idx_scan ASC;

数据库优化没有银弹,先测量再优化。

所有文章

© 2026 Dev Notes