车联网案例,轨迹清洗 - 阿里云RDS PostgreSQL最佳实践 - 窗口查询

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

标签

PostgreSQL , 窗口函数 , 车联网 , 轨迹 , 轨迹清洗 , lag , lead


背景

车联网中一个非常典型的场景是采集车辆的行驶轨迹,通常来说车辆的轨迹并不会实时上报,可能会堆积若干条轨迹记录,或者间隔多少时间上报一次。

一个典型的数据结构如下

(car_id, pos geometry, crt_time timestamp)  

车辆在行驶,行驶过程中会遇到堵车,红绿灯,那么上报的轨迹记录可能是这样的

1, 位置1, '2017-01-01 12:00:00'  
1, 位置1, '2017-01-01 12:00:05'  
1, 位置1, '2017-01-01 12:00:10'  
1, 位置1, '2017-01-01 12:00:15'  
1, 位置1, '2017-01-01 12:00:20'  
1, 位置2, '2017-01-01 12:00:30'  

也就是说,在同一个位置,因为堵车、等红灯,可能会导致上传多条记录。

那么就涉及到在数据库中清洗不必要的等待记录的需求,在一个点,我们最多保留2条记录,表示到达这个位置和离开这个位置。

这个操作可以使用窗口函数实现。

当然从最佳效率角度来分析,轨迹清洗这个事情,在终端做是更合理的,一个位置的起始点,只留两条。

例子

1、设计表结构

create table car_trace (cid int, pos point, crt_time timestamp);  

2、生成1000万测试数据,假设有1000量车,(为了让数据更容易出现重复,为了测试看效果,位置使用25个点)

insert into car_trace select random()*999, point((random()*5)::int, (random()*5)::int), clock_timestamp() from generate_series(1,10000000);  

3、创建索引

create index idx_car on car_trace (cid, crt_time);  

4、查询数据layout

select * from car_trace where cid=1 order by crt_time limit 1000;  
  
   1 | (3,1) | 2017-07-22 21:30:09.84984  
   1 | (1,4) | 2017-07-22 21:30:09.850297  
   1 | (1,4) | 2017-07-22 21:30:09.852586  
   1 | (1,4) | 2017-07-22 21:30:09.854155  
   1 | (1,4) | 2017-07-22 21:30:09.854425  
   1 | (3,1) | 2017-07-22 21:30:09.854493  
  
观察到了几个重复。  

5、使用窗口过滤单一位置记录,最多仅保留到达这个位置和离开这个位置的两条记录。

这里用到两个窗口函数:

lag,表示当前记录的前面一条记录。

lead,表示当前记录的下一条记录。

判断到达点、离去点的方法如下:

  • 当前pos 不等于 前一条pos,说明这条记录是当前位置的到达点。

  • 当前pos 不等于 下一条pos,说明这条记录是当前位置的离去点。

  • 前一条pos 为空,说明这条记录是第一条记录。

  • 下一条pos 为空,说明这条记录是最后一条记录。

select * from   
(  
select   
  *,   
  lag(pos) over (partition by cid order by crt_time) as lag,   
  lead(pos) over (partition by cid order by crt_time) as lead   
from car_trace   
  where cid=1   
  and crt_time between '2017-07-22 21:30:09.83994' and '2017-07-22 21:30:09.859735'  
) t  
  where pos <> lag  
  or pos <> lead  
  or lag is null  
  or lead is null;  
  
 cid |  pos  |          crt_time          |  lag  | lead    
-----+-------+----------------------------+-------+-------  
   1 | (2,1) | 2017-07-22 21:30:09.83994  |       | (3,1)  
   1 | (3,1) | 2017-07-22 21:30:09.839953 | (2,1) | (5,2)  
   1 | (5,2) | 2017-07-22 21:30:09.840704 | (3,1) | (4,4)  
   1 | (4,4) | 2017-07-22 21:30:09.84179  | (5,2) | (5,2)  
   1 | (5,2) | 2017-07-22 21:30:09.843787 | (4,4) | (1,5)  
   1 | (1,5) | 2017-07-22 21:30:09.844165 | (5,2) | (0,5)  
   1 | (0,5) | 2017-07-22 21:30:09.84536  | (1,5) | (4,1)  
   1 | (4,1) | 2017-07-22 21:30:09.845896 | (0,5) | (3,3)  
   1 | (3,3) | 2017-07-22 21:30:09.846958 | (4,1) | (3,1)  
   1 | (3,1) | 2017-07-22 21:30:09.84984  | (3,3) | (1,4)  
   1 | (1,4) | 2017-07-22 21:30:09.850297 | (3,1) | (1,4)  
   1 | (1,4) | 2017-07-22 21:30:09.854425 | (1,4) | (3,1)  
   1 | (3,1) | 2017-07-22 21:30:09.854493 | (1,4) | (3,2)  
   1 | (3,2) | 2017-07-22 21:30:09.854541 | (3,1) | (2,0)  
   1 | (2,0) | 2017-07-22 21:30:09.855297 | (3,2) | (4,1)  
   1 | (4,1) | 2017-07-22 21:30:09.857592 | (2,0) | (4,1)  
   1 | (4,1) | 2017-07-22 21:30:09.857595 | (4,1) | (0,4)  
   1 | (0,4) | 2017-07-22 21:30:09.857597 | (4,1) | (3,1)  
   1 | (3,1) | 2017-07-22 21:30:09.858996 | (0,4) | (3,1)  
   1 | (3,1) | 2017-07-22 21:30:09.859735 | (3,1) |   
(20 rows)  

未加清洗轨迹,得到的结果如下:

select   
  *,   
  lag(pos) over (partition by cid order by crt_time) as lag,   
  lead(pos) over (partition by cid order by crt_time) as lead   
from car_trace   
  where cid=1   
  and crt_time between '2017-07-22 21:30:09.83994' and '2017-07-22 21:30:09.859735';  
  
 cid |  pos  |          crt_time          |  lag  | lead    
-----+-------+----------------------------+-------+-------  
   1 | (2,1) | 2017-07-22 21:30:09.83994  |       | (3,1)  
   1 | (3,1) | 2017-07-22 21:30:09.839953 | (2,1) | (5,2)  
   1 | (5,2) | 2017-07-22 21:30:09.840704 | (3,1) | (4,4)  
   1 | (4,4) | 2017-07-22 21:30:09.84179  | (5,2) | (5,2)  
   1 | (5,2) | 2017-07-22 21:30:09.843787 | (4,4) | (1,5)  
   1 | (1,5) | 2017-07-22 21:30:09.844165 | (5,2) | (0,5)  
   1 | (0,5) | 2017-07-22 21:30:09.84536  | (1,5) | (4,1)  
   1 | (4,1) | 2017-07-22 21:30:09.845896 | (0,5) | (3,3)  
   1 | (3,3) | 2017-07-22 21:30:09.846958 | (4,1) | (3,1)  
   1 | (3,1) | 2017-07-22 21:30:09.84984  | (3,3) | (1,4)  
   1 | (1,4) | 2017-07-22 21:30:09.850297 | (3,1) | (1,4)  
   1 | (1,4) | 2017-07-22 21:30:09.852586 | (1,4) | (1,4)  
   1 | (1,4) | 2017-07-22 21:30:09.854155 | (1,4) | (1,4)  
   1 | (1,4) | 2017-07-22 21:30:09.854425 | (1,4) | (3,1)  
   1 | (3,1) | 2017-07-22 21:30:09.854493 | (1,4) | (3,2)  
   1 | (3,2) | 2017-07-22 21:30:09.854541 | (3,1) | (2,0)  
   1 | (2,0) | 2017-07-22 21:30:09.855297 | (3,2) | (4,1)  
   1 | (4,1) | 2017-07-22 21:30:09.857592 | (2,0) | (4,1)  
   1 | (4,1) | 2017-07-22 21:30:09.857595 | (4,1) | (0,4)  
   1 | (0,4) | 2017-07-22 21:30:09.857597 | (4,1) | (3,1)  
   1 | (3,1) | 2017-07-22 21:30:09.858996 | (0,4) | (3,1)  
   1 | (3,1) | 2017-07-22 21:30:09.859735 | (3,1) |   
(22 rows)  

使用lag, lead清洗掉了停留过程中的记录。

被跟踪对象散落导致的扫描IO放大的优化

因为业务中涉及的车辆ID可能较多,不同车辆汇聚的数据会往数据库中写入,如果不做任何优化,那么不同车辆的数据进入数据库后,可能是交错存放的,也就是说一个数据块中,可能有不同车辆的数据。

那么在查询单一车辆的轨迹时,会扫描很多数据块(扫描IO放大)。

优化思路有两种。

1、业务端汇聚分组排序后写入数据库。例如程序在接收到车辆终端提交的数据后,按车辆ID分组,按时间排序,写入数据库(insert into tbl values (),(),...();)。这样的话,同样车辆的数据,可能会尽可能的落在同一个数据块内。

2、数据库端使用分区,重组数据。例如,按车辆ID,每辆车、或者车辆HASH分区存放。

以上两种方法,都是要将数据按查询需求重组,从而达到降低扫描IO的目的。

这个方法与《PostgreSQL 证券行业数据库需求分析与应用》的方法类似,有兴趣的朋友可以参考。

相关实践学习
基于CentOS快速搭建LAMP环境
本教程介绍如何搭建LAMP环境,其中LAMP分别代表Linux、Apache、MySQL和PHP。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助 &nbsp; &nbsp; 相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
相关文章
|
3天前
|
Cloud Native 关系型数据库 分布式数据库
祝贺!阿里云PolarDB斩获数据库国际顶会ICDE 2024工业赛道最佳论文
阿里云斩获国际顶会ICDE 2024最佳论文,0.5秒实现数据库跨机实例迁移。
祝贺!阿里云PolarDB斩获数据库国际顶会ICDE 2024工业赛道最佳论文
|
5天前
|
关系型数据库 MySQL 数据处理
Mysql 和 PostgreSQL 到底选啥?
Mysql 和 PostgreSQL 到底选啥?
15 0
|
5天前
|
Cloud Native 关系型数据库 分布式数据库
PolarDB是阿里云自主研发的关系型云原生数据库
【5月更文挑战第14天】PolarDB是阿里云自主研发的关系型云原生数据库
45 3
|
5天前
|
SQL 关系型数据库 Serverless
阿里云关系型数据库RDS
阿里云关系型数据库RDS
19 2
|
5天前
|
关系型数据库 分布式数据库 数据库
开源之夏2024学生报名启动!阿里云PolarDB社区项目期待你的参与!
开源之夏2024学生报名启动!阿里云PolarDB社区带你变得更强!
开源之夏2024学生报名启动!阿里云PolarDB社区项目期待你的参与!
|
5天前
|
Cloud Native 关系型数据库 分布式数据库
数据库性能诊断工具DBdoctor通过阿里云PolarDB产品生态集成认证
DBdoctor(V3.1.0)成功通过阿里云PolarDB分布式版(V2.3)集成认证,展现优秀兼容性和稳定性。此工具是聚好看科技的内核级数据库性能诊断产品,运用eBPF技术诊断SQL执行,提供智能巡检、根因分析和优化建议。最新版V3.1.1增加了对PolarDB-X和OceanBase的支持,以及基于cost的索引诊断功能。PolarDB-X是阿里巴巴的高性能云原生分布式数据库,兼容MySQL生态。用户可通过提供的下载地址、在线试用链接和部署指南体验DBdoctor。
154 0
|
5天前
|
Cloud Native 关系型数据库 分布式数据库
|
5天前
|
关系型数据库 MySQL 测试技术
【专栏】PostgreSQL数据库向MySQL迁移的过程、挑战及策略
【4月更文挑战第29天】本文探讨了PostgreSQL数据库向MySQL迁移的过程、挑战及策略。迁移步骤包括评估规划、数据导出与转换、创建MySQL数据库、数据导入。挑战包括数据类型不匹配、函数和语法差异、数据完整性和性能问题。应对策略涉及数据类型映射、代码调整、数据校验和性能优化。迁移后需进行数据验证、性能测试和业务验证,确保顺利过渡。在数字化时代,掌握数据库迁移技能对技术人员至关重要。
|
5天前
|
运维 监控 关系型数据库
Serverless 应用引擎产品使用之在阿里云函数计算(FC)中,要访问另一个账号的rds配置rds的白名单如何解决
阿里云Serverless 应用引擎(SAE)提供了完整的微服务应用生命周期管理能力,包括应用部署、服务治理、开发运维、资源管理等功能,并通过扩展功能支持多环境管理、API Gateway、事件驱动等高级应用场景,帮助企业快速构建、部署、运维和扩展微服务架构,实现Serverless化的应用部署与运维模式。以下是对SAE产品使用合集的概述,包括应用管理、服务治理、开发运维、资源管理等方面。
52 0
|
5天前
|
弹性计算 运维 监控
解密阿里云弹性计算:探索云服务器ECS的核心功能
阿里云ECS是核心计算服务,提供弹性云服务器资源,支持实例按需配置、集群管理和监控,集成安全防护,确保服务稳定、安全,助力高效业务运营。
95 0

相关产品

  • 云数据库 RDS MySQL 版
  • 云原生数据库 PolarDB
  • http://www.vxiaotou.com