
CREATE table ips( ID serial NOT NulL,begin_ip_num bigint,end_ip_num bigint,country_name character varying(255),CONSTRAINT ips_pkey PRIMARY KEY (ID ))
我在begin_ip_num和end_ip_num上添加了索引:
CREATE INDEX index_ips_on_begin_ip_num ON ips USING btree (begin_ip_num );CREATE INDEX index_ips_on_end_ip_num ON ips USING btree (end_ip_num );
使用的查询是:
SELECT "ips".* FROM "ips" WHERE (3065106743 BETWEEN begin_ip_num AND end_ip_num);
问题是我的BETWEEN查询仅使用begin_ip_num上的索引.使用索引后,它使用end_ip_num过滤结果.这是EXPLAIN ANALYZE结果:
Index Scan using index_ips_on_begin_ip_num on ips (cost=0.00..2173.83 rows=27136 wIDth=76) (actual time=16.349..16.350 rows=1 loops=1)Index Cond: (3065106743::bigint >= begin_ip_num)Filter: (3065106743::bigint <= end_ip_num)Rows Removed by Filter: 47596Total runtime: 16.425 ms
我已经尝试了各种索引组合,包括在begin_ip_num和end_ip_num上添加复合索引.
尝试使用 multicolumn index,但第二列的顺序相反:CREATE INDEX index_ips_begin_end_ip_num ON ips (begin_ip_num,end_ip_num DESC);
对于单列索引,排序大多无关紧要,因为它几乎可以快速向后扫描.但它对多列索引很重要.
根据我提出的索引,Postgres可以扫描第一列并找到地址,其中索引的其余部分满足第一个条件.然后,对于第一列的每个值,它可以返回满足第二个条件的所有行,直到第一个列失败.然后跳转到第一列的下一个值,等等.
这仍然不是很有效,Postgres可能更快,只需扫描第一个索引列并过滤第二个索引列.很大程度上取决于您的数据分布.
真正有用的是GiST index for a int8range column,自Postgresql 9.2起可用.
除此之外,你可以看看这个closely related answer on dba.SE与一个相当复杂的制度与部分索引.高级的东西,但它提供了很好的性能.
无论哪种方式,CLUSTER使用上面的多列索引可以帮助提高性能:
CLUSTER ips USING index_ips_begin_end_ip_num
这样,满足您的第一个条件的候选人被打包到相同或相邻的数据页面上.如果第一列的每个值有很多行,可以帮助提高性能.否则它几乎没有效果.
此外,是autovacuum正在运行还是你在桌面上运行ANALYZE?您需要Postgres的当前统计信息来选择适当的查询计划.
总结以上是内存溢出为你收集整理的PostgreSQL索引不用于范围查询全部内容,希望文章能够帮你解决PostgreSQL索引不用于范围查询所遇到的程序开发问题。
如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。
欢迎分享,转载请注明来源:内存溢出
微信扫一扫
支付宝扫一扫
评论列表(0条)