Like表复合索引优化:查询性能异常与最优索引方案问询
问题分析与优化建议
先拆解下你的查询慢的核心原因,再给出针对性的优化方案:
异常点分析
从你提供的查询计划和现有索引来看,主要有这几个问题导致查询耗时过高:
- 索引选择不匹配:你的查询WHERE条件是
object_id = %s AND content_type_id = %s AND "like" = %s,但数据库却选择了单字段的like_417f1b1d(仅content_type_id的索引)。这意味着数据库先扫描所有匹配content_type_id的行(多达127万行),再在这些行里过滤object_id和like字段,这种大范围扫描+事后过滤的方式自然效率极低。 - 现有唯一索引无法被利用:你创建的
like_user_id_uniq索引是(user_id, content_type_id, object_id),但你的查询里并没有指定user_id作为过滤条件。由于索引的前缀匹配原则,数据库无法利用这个索引的后续字段来快速定位数据,相当于这个索引对当前查询完全无效。 - 统计信息可能过时:查询计划里估计返回1行,但索引扫描却返回了127万行,说明数据库的统计信息可能不准确,导致它选错了索引策略。
最优索引方案
针对你的查询场景(检查用户是否点赞某对象、查询点赞用户列表),需要创建匹配WHERE条件的组合索引,推荐两种方案:
方案1:覆盖过滤条件的组合索引
CREATE INDEX idx_like_content_object_like ON "like" USING btree (content_type_id, object_id, "like");
- 索引顺序逻辑:先放等值匹配的
content_type_id和object_id(这两个是精确匹配,基数更高),最后放like布尔字段(用于过滤)。 - 优势:数据库可以直接通过这个索引定位到所有符合
content_type_id + object_id + like条件的行,无需再回表扫描大量数据,直接拿到需要的user_id去关联accounts_user表,大幅降低查询成本。
方案2:包含式组合索引(更轻量化)
如果like字段的基数很低(比如大部分记录都是true或false),可以把它作为包含列,减少索引大小:
CREATE INDEX idx_like_content_object ON "like" USING btree (content_type_id, object_id) INCLUDE ("like");
- 优势:索引只存储
content_type_id和object_id的键值,like作为附加列不参与索引排序,索引体积更小,维护成本更低,同样能满足过滤需求。
额外建议
- 更新统计信息:如果创建新索引后仍然有问题,先更新表的统计信息,让数据库能准确评估索引成本:
ANALYZE "like";
- 避免使用SQL关键字作为表名:
like是SQL的关键字,虽然你用引号括起来没问题,但长期来看容易引发语法错误,建议重命名表(比如改成user_like)。
内容的提问来源于stack exchange,提问作者EralpB
相关产品推荐
相关产品推荐

