我有一个覆盖索引的表,应该只使用索引来响应查询,根本不检查表。事实上,Postgres确实这样做,如果IN()子句中有1或几个元素。但是,如果IN子句有很多元素,它似乎是在索引上进行搜索,然后进入表格并重新检查条件...为什么PostgreSQL根据其IN()子句的内容不使用* just *覆盖索引?
我不明白为什么Postgres会去做。它可以直接从索引提供查询,也可以不提供,如果它(理论上)没有其他要添加的内容,它为什么会进入表格?
表:
CREATE TABLE phone_numbers
(
id serial NOT NULL,
phone_number character varying,
hashed_phone_number character varying,
user_id integer,
created_at timestamp without time zone,
updated_at timestamp without time zone,
ghost boolean DEFAULT false,
CONSTRAINT phone_numbers_pkey PRIMARY KEY (id)
)
WITH (
OIDS=FALSE
);
CREATE INDEX index_phone_numbers_covering_hashed_ghost_and_user
ON phone_numbers
USING btree
(hashed_phone_number COLLATE pg_catalog."default", ghost, user_id);
我跑的查询是:
SELECT "phone_numbers"."user_id"
FROM "phone_numbers"
WHERE "phone_numbers"."hashed_phone_number" IN (*several numbers*)
AND "phone_numbers"."ghost" = 'f'
正如你可以看到,指数有需要回复到该查询的所有字段。
如果我只有一个或IN子句中的几个数字,它的作用:
1号:
索引扫描使用index_phone_numbers_on_hashed_phone_number上PHONE_NUMBERS(成本= 0.41..8.43行= 1米宽度= 4)
指数电导率:((hashed_phone_number)::文本= 'bebd43a6eb29b2fda3bcb63dcc7ffaf5433e78660ccd1a495c1180a3eaaf6b6a' ::文本)
过滤器:(NOT鬼)”
3个数字:
索引只能扫描使用index_phone_numbers_covering_hashed_ghost_and_user上PHONE_NUMBERS(成本= 0.42..17.29行= 1米宽度= 4)
指数电导率:((hashed_phone_number = ANY(” {8228a8116f1fdb12e243102cb85ecd859ebf7873d9332dce5f1343a481ec72e8,43ddeebdca2ea829d468d5debc84d475c8322cf4bf6edca286c918b04216387e,1578bf773eb6eb8a9b57a130922a28c9c91f1bda67202ef5936b39630ca4cfe4}“::文[]))AND(...)
筛选:(不鬼)”
然而,当我IN子句中有很多数字,Postgres的使用指标,但随后打表,我不知道为什么:
位图堆上扫描PHONE_NUMBERS(成本= 926.59..1255.81行数= 106宽度= 4)
重新检查电导率:((hashed_phone_number)::文本= ANY('{b6459ce58f21d99c462b132cce7adc9ea947fa522a3849321e9fb65893006a5e,8228a8116f1fdb12e243102cb85ecd859ebf7873d9332dce5f1343a481ec72e8,ab3554acc1f287bb2e22ff20bb855e19a4177ef552676689d217dbb2a1a6177b,7ec9f58(...)
筛选:(非幻影)
- > index_phone_numbers_covering_hashed_ghost_and_user(cost = 0.00..926。56行= 106宽度= 0)
指数电导率:(((hashed_phone_number)::文本= ANY('{b6459ce58f21d99c462b132cce7adc9ea947fa522a3849321e9fb65893006a5e,8228a8116f1fdb12e243102cb85ecd859ebf7873d9332dce5f1343a481ec72e8,ab3554acc1f287bb2e22ff20bb855e19a4177ef552676689d217dbb2a1a6177b,7E(...)
这是目前正在查询,这是查找一个表中有250个记录在总行数为50k的表中,大约是另一个表上的类似查询的两倍,该查询在具有500万行的表中查找250条记录,没什么意义,
任何想法会发生什么,以及我是否可以做任何事情来改善这种情况?
UPDATE:在覆盖索引改变的列的顺序具有第一重影和然后hashed_phone_number也没有解决它:
位图堆扫描上PHONE_NUMBERS(成本= 926.59 ..1255.81行数= 106宽度= 4)
重新检查电导率:((hashed_phone_number)::文本= ANY('{b6459ce58f21d99c462b132cce7adc9ea947fa522a3849321e9fb65893006a5e,8228a8116f1fdb12e243102cb85ecd859ebf7873d9332dce5f1343a481ec72e8,ab3554acc1f287bb2e22ff20bb855e19a4177ef 552676689d217dbb2a1a6177b,7ec9f58(...)
过滤器:(NOT鬼)
- >位图索引扫描index_phone_numbers_covering_ghost_hashed_and_user(成本= 0.00..926.56行数= 106宽度= 0)
指数电导率:((鬼= FALSE)AND((hashed_phone_number)::文本= ANY('{b6459ce58f21d99c462b132cce7adc9ea947fa522a3849321e9fb65893006a5e,8228a8116f1fdb12e243102cb85ecd859ebf7873d9332dce5f1343a481ec72e8,ab3554acc1f287bb2e22ff20bb855e19a4177ef55267668(...)
即使“幽灵”是一个“低选择性”列吗? (大约一半的行是鬼,一半都没有)。我认为最好先设置hashed_phone_number,因为这些选项非常有选择性(它们本质上是一个唯一的键)。我会尝试你的方式,并报告回来。谢谢! –
我刚刚尝试用ghost重新创建索引,并且仍然显示完全相同的行为(检查问题底部的EXPLAIN的新输出)。此外,独立于此,尽管您的解释是有道理的,但我不明白为什么它会进入表格,如果它具有索引中的信息。即使在“坏”情况下,它*是*使用索引... –
@DanielMagliola。 。 。嗯,有趣的是不起作用。我认为,在一个大的'in'条款中,Postgres只是认为第二个执行计划更有效率。 –