新零售空间数据库实践一例 - PostGIS 点面叠加视觉判断输出

本文涉及的产品
云原生数据库 PolarDB MySQL 版,Serverless 5000PCU 100GB
云原生数据库 PolarDB 分布式版,标准版 2核8GB
云数据库 RDS MySQL Serverless,0.5-2RCU 50GB
简介:

标签

PostgreSQL , 点面视觉输出 , subquery , nestloop join , 空间索引 , gist


背景

在新零售、快递等行业,有大量的点数据(例如包裹位置、快递员位置、仓库位置等),同时有大量的面数据(如小区,商圈,写字楼等)。

如何判断实时的正在配送的包裹落在哪个面呢?并且将之联系起来。

这个从视觉角度来思考,非常简单。

例如有一个地图,将其划分为若干个面(例如前面提到的小区)。

pic

然后有一些小点,这些是POINT数据。

pic

我们从图上一眼就能看出每个点落在哪个小区(面)里面。

在数据库中,这可能是两份数据(一份为点,一份为面)。输出的实际上是点+面(ID)的数据。

怎么做到高效的输出呢?

DEMO

搜索某些订单,当前处于哪个面。这是非常典型的点面判断需求。

接下来的例子,有25万个面,查询若干笔订单属于哪个面。

1、创建、生成静态的面数据(通常面的数据是静态的,例如小区,商圈,大楼,仓库覆盖范围等)

postgres=# create table t2(id int, pos box);  
CREATE TABLE  
  
-- 在(0,0)到(500,500)的平面上,划分成251001个正方形的小面。  
  
postgres=# do language plpgsql $$    
declare  
x int;  
y int;  
begin  
for x in 0..500 loop  
for y in 0..500 loop   
  insert into t2 values (x+y, box(point(x,y),point(x+1,y+1)));  
end loop;  
end loop;  
end;  
$$;  
DO  
  
postgres=# select count(*) from t2;  
 count    
--------  
 251001  
(1 row)  

创建空间索引

postgres=# create index idx_t2 on t2 using gist(pos);
CREATE INDEX

2、创建、生成点的数据。

postgres=# create table t1(id int, pos point);  
CREATE TABLE  
-- 在(0,0),(500,500)的平面上,生成10000个随机的点  
  
postgres=# insert into t1 select id, point(random()*500, random()*500) from generate_series(1,10000) t(id);  
INSERT 0 10000  

3、查询每个点,属于哪个面。

方法1,JOIN

postgres=# explain analyze select t1.*,t2.* from t1 join t2 on (t2.pos @> box(t1.pos, t1.pos));  
                                                       QUERY PLAN                                                         
------------------------------------------------------------------------------------------------------------------------  
 Nested Loop  (cost=0.29..73322.20 rows=2510010 width=56) (actual time=0.094..1191.076 rows=10000 loops=1)  
   ->  Seq Scan on t1  (cost=0.00..116.00 rows=10000 width=20) (actual time=0.020..1.047 rows=10000 loops=1)  
   ->  Index Scan using idx_t2 on t2  (cost=0.29..4.81 rows=251 width=36) (actual time=0.039..0.118 rows=1 loops=10000)  
         Index Cond: (pos @> box(t1.pos, t1.pos))  
 Planning time: 0.102 ms  
 Execution time: 1191.619 ms  
(6 rows)  

方法2,SUBQUERY

postgres=# explain analyze select t1.*, (select t2 from t2 where t2.pos @> box(t1.pos,t1.pos) limit 1) from t1;  
                                                            QUERY PLAN                                                              
----------------------------------------------------------------------------------------------------------------------------------  
 Seq Scan on t1  (cost=0.00..13706.74 rows=10000 width=52) (actual time=0.077..427.466 rows=10000 loops=1)  
   SubPlan 1  
     ->  Limit  (cost=0.29..1.36 rows=1 width=60) (actual time=0.042..0.042 rows=1 loops=10000)  
           ->  Index Scan using idx_t2 on t2  (cost=0.29..269.88 rows=251 width=60) (actual time=0.042..0.042 rows=1 loops=10000)  
                 Index Cond: (pos @> box(t1.pos, t1.pos))  
 Planning time: 0.080 ms  
 Execution time: 427.942 ms  
(7 rows)  

如果是1000笔订单,返回差不多40毫秒

postgres=# explain (analyze,verbose,timing,costs,buffers) select t1.*, (select t2 from t2 where t2.pos @> box(t1.pos,t1.pos) limit 1) from t1 limit 1000;
                                                                  QUERY PLAN                                                                  
----------------------------------------------------------------------------------------------------------------------------------------------
 Limit  (cost=0.00..1370.67 rows=1000 width=52) (actual time=0.069..39.754 rows=1000 loops=1)
   Output: t1.id, t1.pos, ((SubPlan 1))
   Buffers: shared hit=3002
   ->  Seq Scan on public.t1  (cost=0.00..13706.74 rows=10000 width=52) (actual time=0.069..39.658 rows=1000 loops=1)
         Output: t1.id, t1.pos, (SubPlan 1)
         Buffers: shared hit=3002
         SubPlan 1
           ->  Limit  (cost=0.29..1.36 rows=1 width=60) (actual time=0.039..0.039 rows=1 loops=1000)
                 Output: t2.*
                 Buffers: shared hit=3000
                 ->  Index Scan using idx_t2 on public.t2  (cost=0.29..269.88 rows=251 width=60) (actual time=0.039..0.039 rows=1 loops=1000)
                       Output: t2.*
                       Index Cond: (t2.pos @> box(t1.pos, t1.pos))
                       Buffers: shared hit=3000
 Planning time: 0.066 ms
 Execution time: 39.830 ms
(16 rows)

因为@>暂时不支持hash join,因此subquery更优一些。

本文没有用到PostGIS空间数据库插件,而是使用了内置的平面几何类型,用于演示。

真实场景请使用PostGIS。

http://postgis.net/

例如

select  t1.*, (select t2 from t2 where ST_Within(t1.geom, t2.geom) limit 1) from t1;

小结

点面判断在GIS信息崛起的今天,在越来越多的企业中成为了非常常见的需求,比如文中提到的。

PostgreSQL在空间数据库领域有非常丰富的应用,从科研、军工、商业到民用,无处不在。

结合空间索引,BRIN索引实现空间数据的高效率检索是很轻松的事情。

相关文章
|
2月前
|
存储 SQL Web App开发
SQL实践篇(一):使用WebSQL在H5中存储一个本地数据库
SQL实践篇(一):使用WebSQL在H5中存储一个本地数据库
57 2
|
3月前
|
存储 监控 安全
360 企业安全浏览器基于阿里云数据库 SelectDB 版内核 Apache Doris 的数据架构升级实践
为了提供更好的日志数据服务,360 企业安全浏览器设计了统一运维管理平台,并引入 Apache Doris 替代了 Elasticsearch,实现日志检索与报表分析架构的统一,同时依赖 Doris 优异性能,聚合分析效率呈数量级提升、存储成本下降 60%....为日志数据的可视化和价值发挥提供了坚实的基础。
360 企业安全浏览器基于阿里云数据库 SelectDB 版内核 Apache Doris 的数据架构升级实践
|
20天前
|
存储 SQL 数据库
数据库设计案例:电商系统数据库设计实践
数据库设计案例:电商系统数据库设计实践
53 1
|
4天前
|
SQL Java 数据库连接
Java数据库编程实践:连接与操作数据库
Java数据库编程实践:连接与操作数据库
9 0
|
7天前
|
存储 监控 Apache
查询提速11倍、资源节省70%,阿里云数据库内核版 Apache Doris 在网易日志和时序场景的实践
网易的灵犀办公和云信利用 Apache Doris 改进了大规模日志和时序数据处理,取代了 Elasticsearch 和 InfluxDB。Doris 实现了更低的服务器资源消耗和更高的查询性能,相比 Elasticsearch,查询速度提升至少 11 倍,存储资源节省达 70%。Doris 的列式存储、高压缩比和倒排索引等功能,优化了日志和时序数据的存储与分析,降低了存储成本并提高了查询效率。在灵犀办公和云信的实际应用中,Doris 显示出显著的性能优势,成功应对了数据增长带来的挑战。
查询提速11倍、资源节省70%,阿里云数据库内核版 Apache Doris 在网易日志和时序场景的实践
|
13天前
|
存储 算法 数据库
矢量数据库在图像识别与检索中的应用实践
【4月更文挑战第30天】本文探讨了矢量数据库在图像识别与检索中的应用,通过特征提取(如SIFT、SURF)、编码和相似度度量实现快速识别。在图像检索流程中,经过预处理、特征提取和编码后,矢量数据库用于查询相似特征,排序后展示给用户。实际案例显示,矢量数据库能提升电商平台的商品图像搜索效率和用户体验。随着技术发展,这一领域应用前景广阔。
|
20天前
|
数据库
头歌实践平台--数据库原理
头歌实践平台--数据库原理
16 0
|
1月前
|
SQL 监控 数据库
数据库管理与电脑监控软件:SQL代码优化与实践
本文探讨了如何优化数据库管理和使用电脑监控软件以提升效率。通过SQL代码优化,如使用索引和调整查询语句,能有效提高数据库性能。同时,合理设计数据库结构,如数据表划分和规范化,也能增强管理效率。此外,利用Python脚本自动化收集系统性能数据,并实时提交至网站,可实现对电脑监控的实时性和有效性。这些方法能提升信息系统稳定性和可靠性,满足用户需求。
91 0
|
1月前
|
Java 数据处理 调度
更高效准确的数据库内部任务调度实践,阿里云数据库SelectDB 内核 Apache Doris 内置 Job Scheduler 的实现与应用
Apache Doris 2.1 引入了内置的 Job Scheduler,旨在解决依赖外部调度系统的问题,提供秒级精确的定时任务管理。
|
3月前
|
缓存 监控 关系型数据库
构建高效的数据库应用:Python 实践
在当今数据驱动的世界中,构建高效的数据库应用程序对于企业和个人来说至关重要。Python 作为一种强大的编程语言,提供了丰富的数据库工具和库,使得开发人员能够轻松地构建高效、可靠的数据库应用程序。在本文中,我们将探讨一些关键的技术和最佳实践,以帮助你构建高效的数据库应用程序。