【问题标题】:postgresql: implementation of hierarchical treepostgresql:层次树的实现
【发布时间】:2013-04-24 03:09:40
【问题描述】:

我一直在努力解决 1000 多个标记(应该放在谷歌地图上)的标记聚类问题。我不太热衷于使用所有标记渲染大型 JSON 结构,也不喜欢使用 PostGIS 进行一些复杂的服务器“地理”计算。

我想出的解决方案是将世界地图划分为某种分层空间树,比如说quad tree,我的数据库中的每个点都将在该树中分配有“坐标”。这些坐标是具有on position_x index_of_tile in tier_x 的字符串,例如'031232320012'。字符串的长度取决于将为前端地图启用的缩放级别数。基本上,如果用户移动或缩放地图,我将使用当前缩放级别和视口坐标作为参数启动 Ajax GET 请求。然后在后端我计划构建一个应该指向“给定缩放级别的视口”的字符串,例如'02113',我想在树坐标列中找到所有具有此前缀('02113')的点。

编辑:我还需要快速 GROUP BY,例如SELECT count(*) from points GROUP BY left(coordinates, 5);

我的问题是如何尽可能快地执行这些操作?我的数据库是 PostgreSQL。

【问题讨论】:

  • 我会再看看你是否更好地使用 PostgreSQL 的地理支持。您不必全力以赴使用 PostGIS。您可以在最近的版本中对边界框甚至最近邻测试进行索引。如果做不到这一点,下面迈克的回答看起来不错。

标签: postgresql marker hierarchical-clustering quadtree


【解决方案1】:

然后,我计划在后端构建一个字符串,该字符串应指向“给定缩放级别的视口”,例如'02113',我想在树坐标列中找到所有具有此前缀('02113')的点。

只要您查看索引列中字符串最左边的五个(或六个或七个)字符,普通索引就应该在任何现代 dbms 上表现良好。

SELECT ...
...
WHERE column_name LIKE '02113%';

在 PostgreSQL 中,您还可以构建一个index on an expression。所以你可以在前五个字符上创建一个索引。

CREATE INDEX your_index_name ON your_table (left(column_name, 5));

如果有三四个这样的索引,我希望 PostgreSQL 的查询优化器能够选择正确的索引。 (5个字符一个,6个字符一个,等等)


我建立了一个表,并用一百万行随机数据填充了它。

在以下查询中,PostgreSQL 的查询优化器确实选择了正确的索引。

explain analyze
select s
from coords
where left(s, 5) ='12345';

它在 0.1 毫秒内返回。

我还使用 GROUP BY 进行了测试。再次,PostgreSQL 的查询优化器选择了正确的索引。

"GroupAggregate  (cost=0.00..62783.15 rows=899423 width=8) (actual time=91.300..3096.788 rows=90 loops=1)"
"  ->  Index Scan using coords_left_idx1 on coords  (cost=0.00..46540.36 rows=1000000 width=8) (actual time=0.051..2915.265 rows=1000000 loops=1)"
"Total runtime: 3096.914 ms"

left(name, 2) 这样的表达式在 GROUP BY 子句中将要求 PostgreSQL 接触索引中的每一行,如果不是表中的每一行的话。这就是为什么我的查询需要 3096 毫秒;它必须触及索引中的一百万行。但是你可以从 EXPLAIN 计划中看到它使用了索引。

通常,我希望地理应用程序对 PostGIS 表使用边界框来减少您访问的行数。如果你的四叉树实现不能做得比这更好,我会坚持使用 PostGIS 足够长的时间来成为它的专家。 (在你花一些时间之前,你不会确定它不能完成这项工作。)

【讨论】:

  • 表达式上的索引的问题是,这里可能会有超过 10 个索引。我会尝试使用那个普通的索引。
  • 我刚刚意识到我还需要快速分组,例如SELECT count(*) from points GROUP BY left(coords, 5)。有什么方法可以更快地进行分组吗?
  • 索引的数量可能不是问题,但我还没有像你所说的那样构建任何东西。 (不过,它很容易测试。)您可以通过在left(coords, 5) 上创建索引来加快 GROUP BY。索引和 sargable 表达式(实际上可以使用索引的 WHERE 子句)是您提高速度的主要来源。 EXPLAIN ANALYZE SELECT... 是你的朋友。
  • 您确定表达式索引对 GROUP BY 有帮助吗?我的一个测试表上有这个索引:"test" btree ("left"(name::text, 2)),但select count(*) from web_city GROUP BY left(name,2); 的查询计划与没有它时完全相同。
  • ORDER BY 也是如此。虽然如果我做WHERE left(name, 2) = 'ab';,WHERE 会受到索引的影响。
猜你喜欢
  • 1970-01-01
  • 2012-12-12
  • 1970-01-01
  • 2012-08-03
  • 2022-01-26
  • 2017-12-20
  • 1970-01-01
  • 2015-02-06
  • 1970-01-01
相关资源
最近更新 更多