当我想使用这个 sql 来检查是否使用索引时:
explain SELECT id AS id, sub_source_id AS sub_source_id
FROM article
WHERE sub_source_id IN (
select sub_source_id
from sub_relation sr
where user_id =14
and sub_status = 1
) ORDER BY created_time DESC LIMIT 50
显示这样的信息:
Workers Planned: 2
-> Sort (cost=74344.09..74697.64 rows=141422 width=24)
Sort Key: article.created_time DESC
-> Hash Join (cost=77.11..69646.15 rows=141422 width=24)
Hash Cond: (article.sub_source_id = sr.sub_source_id)
-> Parallel Seq Scan on article (cost=0.00..67792.05 rows=675805 width=24)
-> Hash (cost=70.56..70.56 rows=524 width=8)
-> Seq Scan on sub_relation sr (cost=0.00..70.56 rows=524 width=8)
Filter: ((user_id = 14) AND (sub_status = 1))
我已经用 columnsub_source_id
和建立了多列索引created_time
,为什么 sql 没有使用这个article_sub_source_id_create_time_idx
索引?这是表结构:
-- public.article definition
-- Drop table
-- DROP TABLE public.article;
CREATE TABLE public.article (
id int8 NOT NULL GENERATED ALWAYS AS IDENTITY,
user_id int8 NOT NULL,
title varchar(512) NOT NULL,
author varchar(256) NOT NULL,
guid varchar(512) NOT NULL,
created_time int8 NOT NULL,
updated_time int8 NOT NULL,
link varchar(512) NULL,
pub_time timestamptz NULL,
sub_source_id int8 NOT NULL,
cover_image varchar(1024) NULL,
channel_reputation int4 NOT NULL DEFAULT 0,
editor_pick int4 NULL DEFAULT 0,
permanent_store int2 NOT NULL DEFAULT 0,
CONSTRAINT article_id_seq_pk PRIMARY KEY (id),
CONSTRAINT article_title_sub_source_id_key UNIQUE (title, sub_source_id)
);
CREATE INDEX article_sub_source_id_create_time_idx ON public.article USING btree (sub_source_id, created_time);
CREATE INDEX article_title_gin ON public.article USING gin (to_tsvector('english'::regconfig, (title)::text));
CREATE INDEX article_title_zh_gin ON public.article USING gin (to_tsvector('dolphinzhcfg'::regconfig, (title)::text));
当我删除子查询并用静态子源 ID 替换时,外部查询可以使用article_sub_source_id_create_time_idx
索引。
计划者认为您将在应用排序和限制之前获取表的 20%。(这是对的吗?)。使用索引来做这件事可能是个坏主意,除非它可以使用仅索引扫描,或者可以使用排序索引扫描然后提前停止。
要获得仅索引扫描,您需要索引具有用于该表的所有列,
(sub_source_id, created_time, id)
.为了让它使用索引进行排序,created_time 需要是索引中的第一列(或者至少它只需要跟随经过简单相等性测试的列,其中该查询没有)