gpt4 book ai didi

Postgresql索引seq扫描1亿行

转载 作者:行者123 更新时间:2023-11-29 11:22:17 25 4
gpt4 key购买 nike

我遇到一个问题,即已编制索引的查询拒绝使用索引,因为它的选择性不够(假设 1.3 亿行中有 60 行满足条件),因此决定使用 seqscan。

我面临的问题是 seqscan 在这种情况下确实不是最佳选择,出于某种原因它获得了非常好的分数,但事实是 seqscan 只有在之前被查询并且它可以从缓冲区/缓存加载所有内容。

与 seqscan 相比,如果它们都在缓冲区上,索引扫描可能会稍微慢一些,但这种情况很少发生,当两个查询都是冷查询时,索引扫描仍然更快(毫秒对秒)。

请注意,索引扫描更优越,因为我使用了限制子句,因此它应该能够非常快速地获取那几行。

我已将统计值设置为 1000(默认值为 100)并清理以防万一,但情况相同。

TLDR:Seq 扫描与低选择性索引上的索引扫描,seqscan 是首选,但规划器是错误的,seqscan 只有在缓存时才更好,否则会更糟。

查询和计划,注意索引一是从缓冲区加载的,而 seqscan 还没有完全加载。

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'

更新:

表 def(电子邮件和 email_domain 的索引,标准的和 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
)

表统计(真空分析后

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'

最佳答案

你可以使用一个卑鄙的技巧来强制进行索引扫描:

SELECT *
FROM identities_identity
WHERE email_domain IN ('live.com', NULL)
ORDER BY email_domain
LIMIT 100;

如果 PostgreSQL 必须排序,使用索引总是更便宜。

如果你有WHERE email_domain = 'live.com' ,PostgreSQL 足够聪明,知道它不需要排序,这就是为什么我添加了第二个无用的项目来愚弄它。

关于Postgresql索引seq扫描1亿行,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46800338/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com