我遇到了一个问题,即一个已被索引的查询拒绝使用索引,因为它不够具有选择性(假设符合条件的仅有1.3亿行中的60行),所以决定使用顺序扫描。
我面临的问题是,在这种情况下,顺序扫描确实不是最佳选择,由于某种原因,它得分很高,但事实上,只有在之前查询过并且能够从缓存中加载所有内容时才能快速运行。
如果两者都在缓存中,索引扫描可能会稍微慢一些与顺序扫描相比,但这种情况很少发生,并且当两个查询都是“cold”时,索引扫描仍然比顺序扫描快得多(毫秒和秒的差距)。
请注意,索引扫描更优越,因为我使用了限制子句,所以它应该能够非常快地获取那些少数行。
我将统计信息设置为1000(默认值为100)并进行了清理,但结果相同。
总之,对于选择性较低的索引,顺序扫描与索引扫描的比较中,规划程序会错误地选择顺序扫描。只有当它被缓存时,顺序扫描才更好,否则它会更糟糕。
查询和计划,请注意索引一个从缓存中加载而顺序扫描没有完全加载。
我面临的问题是,在这种情况下,顺序扫描确实不是最佳选择,由于某种原因,它得分很高,但事实上,只有在之前查询过并且能够从缓存中加载所有内容时才能快速运行。
如果两者都在缓存中,索引扫描可能会稍微慢一些与顺序扫描相比,但这种情况很少发生,并且当两个查询都是“cold”时,索引扫描仍然比顺序扫描快得多(毫秒和秒的差距)。
请注意,索引扫描更优越,因为我使用了限制子句,所以它应该能够非常快地获取那些少数行。
我将统计信息设置为1000(默认值为100)并进行了清理,但结果相同。
总之,对于选择性较低的索引,顺序扫描与索引扫描的比较中,规划程序会错误地选择顺序扫描。只有当它被缓存时,顺序扫描才更好,否则它会更糟糕。
查询和计划,请注意索引一个从缓存中加载而顺序扫描没有完全加载。
explain (analyze, buffers)
select *
from identities_identity
where email_domain = 'live.com'
limit 100
'Limit (cost=0.00..63.50 rows=100 width=573) (actual time=75215.573..75215.640 rows=100 loops=1)'
' Buffers: shared hit=75113 read=588870'
' -> Seq Scan on identities_identity (cost=0.00..2980008.00 rows=4692733 width=573) (actual time=75215.571..75215.604 rows=100 loops=1)'
' Filter: ((email_domain)::text = 'live.com'::text)'
' Rows Removed by Filter: 54464136'
' Buffers: shared hit=75113 read=588870'
'Planning time: 0.097 ms'
'Execution time: 75215.675 ms'
'Limit (cost=0.57..187.26 rows=100 width=573) (actual time=0.027..0.090 rows=100 loops=1)'
' Buffers: shared hit=6'
' -> Index Scan using identities_identity_email_domain_9056bd28 on identities_identity (cost=0.57..8760978.66 rows=4692733 width=573) (actual time=0.026..0.057 rows=100 loops=1)'
' Index Cond: ((email_domain)::text = 'live.com'::text)'
' Buffers: shared hit=6'
'Planning time: 0.078 ms'
'Execution time: 0.124 ms'
更新:
表定义(包含电子邮件和电子邮件域的索引,分别是标准索引和varchar_pattern_ops索引)
CREATE TABLE public.identities_identity
(
id bigint NOT NULL DEFAULT nextval('identities_identity_id_seq'::regclass),
email character varying(1000) COLLATE pg_catalog."default",
email_domain character varying(1000) COLLATE pg_catalog."default",
leak_id bigint NOT NULL,
CONSTRAINT identities_identity_pkey PRIMARY KEY (id),
CONSTRAINT identities_identity_leak_id_87e1ae4e_fk_identities_leak_id FOREIGN KEY (leak_id)
REFERENCES public.identities_leak (id) MATCH SIMPLE
ON UPDATE NO ACTION
ON DELETE NO ACTION
DEFERRABLE INITIALLY DEFERRED
)
表统计信息(执行vacuum analyze之后)
attname, avg_width, n_distinct, correlation
'id',8,'-1','0.999988'
'email',23,'-0.636853','-0.020479'
'email_domain',10,'3876','0.696452'
'leak_id',8,'1','1'
set enable_seqscan = false;
吗?https://www.postgresql.org/docs/current/static/runtime-config-query.html - Dave Grayenable_seqscan=off
更好的方法... - Laurenz Albeemail_domain
的基数是多少?