gpt4 book ai didi

postgresql - 结合多个索引的 Postgres

转载 作者:行者123 更新时间:2023-11-29 11:27:44 34 4
gpt4 key购买 nike

我有以下表格/索引 -

CREATE TABLE test
(
coords geography(Point,4326),
user_id varchar(50),
created_at timestamp
);
CREATE INDEX ix_coords ON test USING GIST (coords);
CREATE INDEX ix_user_id ON test (user_id);
CREATE INDEX ix_created_at ON test (created_at DESC);

这是我要执行的查询:

select * 
from updates
where ST_DWithin(coords, ST_MakePoint(-126.4, 45.32)::geography, 30000)
and user_id='3212312'
order by created_at desc
limit 60

当我运行查询时,它只使用 ix_coords 索引。我如何确保 Postgres 也使用 ix_user_idix_created_at 索引进行查询?

这是我在其中批量插入生产数据的新表。 test 表中的总行数:15,069,489

我正在使用 (effective_cache_size = 2GB) 运行 PostgreSQL 9.2.1(使用 Postgis)。这是我的本地 OSX,配备 16GB RAM、Core i7/2.5 GHz、非 SSD 磁盘。

添加 EXPLAIN ANALYZE 输出 -

Limit  (cost=71.64..71.65 rows=1 width=280) (actual time=1278.652..1278.665 rows=60 loops=1)
-> Sort (cost=71.64..71.65 rows=1 width=280) (actual time=1278.651..1278.662 rows=60 loops=1)
Sort Key: created_at
Sort Method: top-N heapsort Memory: 33kB
-> Index Scan using ix_coords on test (cost=0.00..71.63 rows=1 width=280) (actual time=0.198..1278.227 rows=178 loops=1)
Index Cond: (coords && '0101000020E61000006666666666E63C40C3F5285C8F824440'::geography)
Filter: (((user_id)::text = '4f1092000b921a000100015c'::text) AND ('0101000020E61000006666666666E63C40C3F5285C8F824440'::geography && _st_expand(coords, 30000::double precision)) AND _st_dwithin(coords, '0101000020E61000006666666666E63C40C3F5285C8F824440'::geography, 30000::double precision, true))
Rows Removed by Filter: 3122459
Total runtime: 1278.701 ms

更新:

根据下面的建议,我尝试在 cords + user_id 上建立索引:

CREATE INDEX ix_coords_and_user_id ON updates USING GIST (coords, user_id);

..但出现以下错误:

ERROR:  data type character varying has no default operator class for access method "gist"
HINT: You must specify an operator class for the index or define a default operator class for the data type.

更新:

因此 CREATE EXTENSION btree_gist; 解决了 btree/gist 复合索引问题。现在我的索引看起来像

CREATE INDEX ix_coords_user_id_created_at ON test USING GIST (coords, user_id, created_at);

注意:btree_gist 不接受 DESC/ASC。

新查询计划:

Limit  (cost=134.99..135.00 rows=1 width=280) (actual time=273.282..273.292 rows=60 loops=1)
-> Sort (cost=134.99..135.00 rows=1 width=280) (actual time=273.281..273.285 rows=60 loops=1)
Sort Key: created_at
Sort Method: quicksort Memory: 41kB
-> Index Scan using ix_updates_coords_user_id_created_at on updates (cost=0.00..134.98 rows=1 width=280) (actual time=0.406..273.110 rows=115 loops=1)
Index Cond: ((coords && '0101000020E61000006666666666E63C40C3F5285C8F824440'::geography) AND ((user_id)::text = '4e952bb5b9a77200010019ad'::text))
Filter: (('0101000020E61000006666666666E63C40C3F5285C8F824440'::geography && _st_expand(coords, 30000::double precision)) AND _st_dwithin(coords, '0101000020E61000006666666666E63C40C3F5285C8F824440'::geography, 30000::double precision, true))
Rows Removed by Filter: 1
Total runtime: 273.331 ms

查询的性能比以前好,快了将近一秒钟,但仍然不是很好。我想这是我能得到的最好的??我希望在 60-80 毫秒左右。还从查询中获取 order by created_at desc,又节省了 100 毫秒,这意味着它无法使用索引。无论如何要解决这个问题?

最佳答案

我不知道 Pg 是否可以将 GiST 索引和常规 b 树索引与位图索引扫描结合起来,但我怀疑不能。如果不向 GiST 索引添加 user_id 列,您可能会得到最好的结果(因此对于其他不使用 user_id 的查询来说,它会变得更大更慢) .

作为实验,您可以:

CREATE EXTENSION btree_gist;
CREATE INDEX ix_coords_and_user_id ON test USING GIST (coords, user_id);

这可能会产生一个大索引,但可能会增加该查询 - 如果它有效。请注意,维护这样的索引会显着降低 INSERTUPDATE 的速度。如果您删除旧的 ix_coords,您的查询将使用 ix_coords_and_user_id,即使它们不过滤 user_id,但它会比 ix_坐标。保留两者会使 INSERTUPDATE 速度变慢。

参见 btree-gist


(被完全改变问题的问题编辑所废弃;当编写用户有一个多列索引时,他们现在已经分成两个单独的索引):

您似乎没有对 user_id 进行过滤或排序,只有 create_date。 Pg 不会(不能?)只使用多列索引的第二项,如 (user_id, create_date),它也需要使用第一项。

如果你想索引create_date,为它创建一个单独的索引。如果您使用并需要 (user_id, create_date) 索引并且通常不单独使用 user_id,请查看是否可以反转列顺序。交替创建两个独立的索引,(user_id)(create_date)。当需要两列时,Pg 可以使用位图索引扫描组合两个独立的索引。

关于postgresql - 结合多个索引的 Postgres,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12701193/

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