基于PostGIS的慢查询引起的空间索引提升实践

目录

前言

一、问题定位

1、前端接口定位

2、后台应用定位

3、找到问题所在

二、空间索引优化

1、数据库查询

2、创建空间索引

3、geography索引

4、再看前端响应

总结


前言

        这是一个真实的案例,也是一个新入门的工程师很容易忽略的点。往往在设计数据库的时候忘了进行索引的构建,进而由此导致了查询的性能很拉胯。下面来简单还原一下事件的经过。在之前的博客中,原文博客地址如下:基于SpringBoot和PostGIS的震中影响范围可视化实践、解决Thymeleaf的地震震中距离展示[[]]双引号报错的问题,这两篇博客中都详细介绍了如何进行空间查询的实战。

        在这些应用的建设过程当中,在进行震中范围定位时,我们发现了一个问题,就是页面请求后端的时间比较长,界面要等很久才能获取结果。 下面是我们进行网络跟踪的结果。

        通过观察network网络请求可以很直观的看到,有一个接口的请求时间很慢,就是获取震中位置的接口最慢的接近4秒才返回数据。 到底是什么原因导致了请求这么慢呢?

        本文将详细分析在PostGIS中,怎么排查数据查询慢接口,如何进行空间索引的构建,以及使用空间索引的正确姿势,通过空间索引的构建提升空间查询的效率。对致力于空间查询优化的小伙伴们有一定的参考价值。闲言少叙,下面正式进入正题。

一、问题定位

        对于一个工程师而言,遇到问题是家常便饭。比如上面这个慢查询的问题,首先这个问题很容易重现,只要点击一个地震信息点,就会请求后台。我们通过去后台调试查看具体的问题。从前端作为入口,到后台方法的定义。我们来谈谈如何进行接口调试,以至于定位查询慢的问题。

1、前端接口定位

        在浏览器中打开调试窗口,在刚刚打开的调试窗口中,可以看到网络请求一栏。在这一栏中,我们可以看到访问比较慢的接口地址。

        这里可以看到很详细的请求地址,下面将参数列出来: 

序号参数名
1request urlhttp://192.168.31.64:8080/earthqadmin/eq/mapview/villageinfo
2request methodpost
3payloadlng 117.03 lat 34.32

        通过这里的请求url,我们可以找到后台对应的接口。由于这里没有采用网关模式部署,因此直接对接的是系统后台。

2、后台应用定位

        在后台代码当中,我们找到对应的controller类,并找到了对应的方法定义,接口代码如下:

/**
* 震中位置5公里分析
* @param lng 经度
* @param lat 纬度
* @return
*/
@PostMapping("/villageinfo")
@ResponseBody
public AjaxResult earthinfo(String lng,String lat){List<EarthquakeVillageVo> list = earthquakeInfoService.findListByLngLat(lng, lat);AjaxResult ar = AjaxResult.success();ar.put("data", list);return ar;
}

        代码比较简单,直接接收参数,并将参数传递到service层(这里并不会消耗时间),我们来看看Service的定义。

@Override
public List<EarthquakeVillageVo> findListByLngLat(String lng, String lat) {return villageMapper.findListByLngLat(" 'point(" +lng+" "+lat+")' ");
}

        通过代码发现,这里也没有进行复杂计算,继续来看Mapper的处理逻辑:

static final String FIND_LIST_BY_LNG_LAT = "<script>"+ "with bp as ( select st_geomfromtext(${pointinfo},4326) :: geography tp ) "+ "select st_distance(t.geom :: geography, bp.tp) dist,t.address,t.village_name,t.lng,t.lat from biz_village t, "+ " bp where st_dwithin(t.geom :: geography, bp.tp, 5000 ) order by dist "+ "</script>";
@Select(FIND_LIST_BY_LNG_LAT)
List<EarthquakeVillageVo> findListByLngLat(@Param("pointinfo")String pointinfo);

3、找到问题所在

        通过接口的代码分析,我们发现其逻辑非常简单,最终只是去数据库进行空间查询。那由此我们可以将问题排查的方向从应用代码转移到数据库中。应该是数据库的查询性能导致了查询性能的下降。顺着这种思路,我们来进行数据库调优,尝试优化查询性能。

二、空间索引优化

        为了验证我们的猜想,也同时为了让系统性能有一个提升,我们将执行的sql语句复制到navicate中进行性能验证。sql语句如下:

with bp as 
(select st_geomfromtext('point(111.99 40.34)',4326) :: geography tp
)
select st_distance(t.geom :: geography, bp.tp),t.*  from biz_village t,bp  where st_dwithin(t.geom :: geography, bp.tp, 5000);

1、数据库查询

        数据库的表biz_village表的数据量在65W左右,这个量其实不算大。毕竟空间数据,上千万条数据都是有可能的。

        首先我们在客户端工具navicate中执行上述语句,看一下实际的查询性能怎么样?来看一下实际的运行结果。执行时间1.79秒,确实有点慢。

         上述语句在数据库中执行,确实比较慢,一共耗时1.8秒,导致后台接口的性能很差。由此证明我们的优化方向是正确的,的确是数据查询性能低导致访问慢。因此问题的关键就变成了查询优化。通常在数据库中的优化步骤是什么呢?优化成本最低的是索引。我们来看一下实际语句,这里用到一个空间函数st_dwithin()。

with bp as 
(select st_geomfromtext('point(111.99 40.34)',4326) :: geography tp
)
select st_distance(t.geom :: geography, bp.tp),t.*  from biz_village t,bp  where st_dwithin(t.geom :: geography, bp.tp, 5000);

        首先我们来看一下数据库表索引,

         惊讶的发现,表里面没有设计空间索引,因此来看一下执行执行计划:

        很明显,这里面没有任何的索引生效,似乎查询慢也是意料之中。既然怀疑是索引问题,那么我们来创建数据库索引。

2、创建空间索引

        这里使用以下语句进行空间所用的创建,创建索引耗时将近10秒。这也是为什么索引要提前创建,不然这些索引创建的时间成本也是挺高的,随着数据量的增大是个很恐怖的数字。

create index idx_biz_village_geom on biz_village using gist(geom)
> OK
> 时间: 9.447s

        在创建了空间索引后,来看一下查询性能是否提升。

        然而并没有什么提升,难道是索引无效吗?继续打开执行计划看一下。发现其依然没有走索引。是不是很奇怪。

         肯定有细心的朋友发现了问题,我们仔细来看一下where条件。

where st_dwithin(t.geom :: geography, bp.tp, 5000);

         在st_dwithin函数中,我们把原本的geometry类型转换为了geography,之所以转换是因为我们想精确计算范围,比如5公里。众所周知,在4326坐标系下,如果使用geomerty的距离计算单位是度,而不是我们熟悉的米。我们先将转换去掉,先来验证索引是否有效。

        仔细对比一下之前的查询计划,发现这里用到了索引查询,0.1表示0.1度,并不是0.1米。请各位朋友注意。 再来执行以下sql语句,是不是很惊喜,查询时间只需要0.006秒。这说明空间索引的构建对于提升空间查询速度帮助很大。

3、geography索引

        这里需要思考一个问题,我们给geometry设计了索引,那geography为什么没有用呢?这也好理解,这两个其实都是空间数据库中空间数据的两种表达。使用geography主要为了精确的计算距离,而使用度来转换的话,不同坐标系下会有一定的误差。但是怎么进行geography的数据索引构建呢?可以使用下面语句来进行。

create index idx_biz_village_geom_gp on biz_village using gist((geom::geography))
> OK
> 时间: 10.513s

        空间索引创建完毕后,再来看执行计划:

        再次执行空间查询,效果依然很明显。优化后执行时间耗时0.009秒。

        从1.8秒到0.009秒,速度提升了 200倍。

4、再看前端响应

        经过上述的空间索引优化后,我们来看一下界面的展示情况。经过数据库优化,界面访问速度大幅提升,可以实现毫秒级响应。用户体验进一步的提升。

总结

        在应用程序的开发过程中,一定要重视索引的使用和创建,好的索引应用能提升应用的查询性能。不好的索引设计,将会使用户体验大大降低。最后提一点最佳实践建议,针对于空间索引,一定要提前建立,因为空间索引的创建耗时太长。在上述的空间索引中,既有geometry的空间索引,又有geography的索引,个人建议,如果不是为了精确计算米级查询,只需要创建geometry索引即可。这样也减少空间索引的创建成本。

        以上就是本文的主要内容,本文将详细分析在PostGIS中,怎么排查数据查询慢接口,如何进行空间索引的构建,以及使用空间索引的正确姿势,通过空间索引的构建提升空间查询的效率。对致力于空间查询优化的小伙伴们有一定的参考价值。行文仓促,定有不当之处,如有不当之处,欢迎各位专家和朋友批评指正,十分感谢。在空间索引优化过程中参考了以下博客资料,站在巨人的肩膀上,才能看得更高更远。

参考资料地址:

1、postgis性能优化实战之-周边搜索查询

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/699107.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

NestJS入门4:MySQL typeorm 增删改查

前文参考&#xff1a; NestJS入门1 NestJS入门2&#xff1a;创建模块 NestJS入门3&#xff1a;不同请求方式前后端写法 1. 安装数据库相关模块 npm install nestjs/typeorm typeorm mysql -S 2. MySql中创建数据库 ​ 3. 添加连接数据库代码 app.module.ts ​ import { M…

给自己留个备忘,blender是右手坐标系

所谓右手坐标系&#xff0c;就是三个轴的方向和右手三根手指的方向一致&#xff08;当然&#xff0c;有要求的&#xff0c;这个要求是大拇指指向x轴方向&#xff0c;食指指向y轴方向,中指指向z轴方向&#xff09;。 不过blender默认是z轴朝上的&#xff0c;如下图。 右手坐标系…

element导航菜单el-menu添加搜索功能

element导航菜单-侧栏&#xff0c;自带的功能没有搜索或者模糊查询。 找了找资料 找到一个比较可行的&#xff0c;记录一下&#xff1a; //index.vue的代码 <div style"overflow:auto"><el-menu :default-active"$route.path":default-openeds&…

<网络安全>《49 网络攻防专业课<第十三课 - 华为防火墙的使用(2)>

6 防火墙的防范技术 6.1 ARP攻击防范 攻击介绍 攻击者通过发送大量伪造的ARP请求、应答报文攻击网络设备&#xff0c;主要有ARP缓冲区溢出攻击和ARP拒绝服务攻击两种。 ARP Flood攻击&#xff08;ARP扫描攻击&#xff09;&#xff1a;攻击者利用工具扫描本网段或者跨网段主机时…

构造器详解

定义: 是一种特殊类型的方法&#xff0c;用于创建对象时初始化对象的状态。 使用new关键字创建对象 构造器特点: 1.和类名相同 2.没有返回值 public class Person {String name;public Person() {this.name"John";}}public class Test {public static void main…

vue2+element医院安全(不良)事件报告管理系统源代码

目录 安全不良事件类型 源码技术栈 医院安全&#xff08;不良&#xff09;事件报告管理系统采用无责的、自愿的填报不良事件方式&#xff0c;有效地减轻医护人员的思想压力&#xff0c;实现以事件为主要对象&#xff0c;可以自动、及时、实际地反应医院的安全、不良、近失事件…

测试环境搭建整套大数据系统(六:搭建sqoop)

一&#xff1a;下载安装包 https://archive.apache.org/dist/sqoop/ 二&#xff1a;解压修改配置。 tar -zxvf sqoop-1.4.7.bin__hadoop-2.6.0.tar.gz -C /opt cd /opt mv sqoop-1.4.7.bin__hadoop-2.6.0/ sqoop-1.4.7修改环境变量 vi /etc/profile#SQOOP_HOME export SQOOP_…

nginx-------- 高性能的 Web服务端 (四)

一、高级配置 1 .1网页的状态页 基于nginx 模块 ngx_http_stub_status_module 实现&#xff0c;在编译安装nginx的时候需要添加编译参数 --with-http_stub_status_module&#xff0c;否则配置完成之后监测会是提示语法错误注意: 状态页显示的是整个服务器的状态,而非虚拟主机…

【Android 性能优化:内存篇】——ExoPlayer 释放后内存没有恢复问题探索

背景 最近笔者承接项目的内存优化指标&#xff0c;在内存调研的过程中发现项目中视频播放结束后&#xff0c;内存没有恢复到播放前到水平。项目中用的 EXO 版本为2.19.1&#xff0c;并且笔者自己也写了个简单的 Demo&#xff0c;发现也是如此。虽然有一些偏门方法可以优化&…

4 buuctf解题

[CISCN 2019 初赛]Love Math1 打开题目 题目源码 <?php error_reporting(0); //听说你很喜欢数学&#xff0c;不知道你是否爱它胜过爱flag if(!isset($_GET[c])){show_source(__FILE__); }else{//例子 c20-1$content $_GET[c];if (strlen($content) > 80) {die("…

无人机的视频图传技术

在操控无人机时&#xff0c;视频图传技术显得尤为关键。通过这项技术&#xff0c;无人机的摄像头所捕捉的画面能实时回传至遥控器&#xff0c;使操作者全面掌握无人机的拍摄情况。同时&#xff0c;无人机图传技术也是衡量无人机性能的重要标准&#xff0c;它关乎飞行距离与时间…

【Vuforia+Unity】AR07-实现识别条码、二维码内容功能(Barcode Scanner)

Barcode Scanner in Unity | Vuforia Library官方教程&#xff0c;写的很详细&#xff0c;本教程主要参考对象&#xff01; 主要实现扫描生活中常见的二维码&#xff0c;然后弹出二维码链接&#xff0c;当然我们也可以再次回调自定义函数&#xff0c;弹出数字内容&#xff0c;…

编译GreatSQL with RocksDB引擎

GreatSQL里也能用上RocksDB引擎 1. 前言 RocksDB 是基于Facebook 开源的一种支持事务的、高度可压缩、高性能的MyRocks存储引擎&#xff0c;特别适用于高度压缩和大容量的数据。以下是一些关键特点&#xff1a; 高性能&#xff1a; LSM 树结构使得RocksDB在写入密集型负载下表现…

剪辑视频调色软件有哪些 剪辑视频软件哪个最好 剪辑视频怎么学 剪辑视频的方法和步骤 会声会影2024 会声会影视频制作教程

看了很多调色教程&#xff0c;背了一堆调色参数&#xff0c;可最终还是调不出理想的效果。别再怀疑自己了&#xff0c;不是你的剪辑技术不行&#xff0c;而是剪辑软件没选对。只要掌握了最基本的调色原理&#xff0c;一款适合自己的视频剪辑软件是很容易出片的。 有关剪辑视频…

python实现维特比算法

对于维特比算法&#xff0c;首先想到的就是高通公司&#xff0c;对于现在的通信行业的两大巨头公司之一&#xff0c;高通公司的发家是由器创始人维特比发明了一种高效的通信解码技术&#xff0c;维特比算法。 对于维特比算法是什么&#xff0c;以一个例子来讲述什么是维特比算…

如何查看Linux中运行了哪些应用

在Linux中&#xff0c;有多种方法可以查看正在运行的应用程序。以下是一些常用的命令&#xff1a; ps 命令&#xff1a;ps 命令用于显示当前终端会话中运行的进程。要查看系统上运行的所有进程&#xff0c;可以使用 -e 或 -A 选项。例如&#xff1a; ps -e或 ps -A这将列出所有…

TiDB离线部署、Tiup部署TiDB

先做tidb准备工作&#xff1a; 部署 TiDB 前的环境检查操作&#xff1a;TiDB 环境与系统配置检查 | PingCAP 文档中心 1.查看数据盘 fdisk -l &#xff08;2,3&#xff09;本人的分区已经是 ext4 文件系统不用分区&#xff0c;具体官方文档的分区&#xff1a; 4.查看数据盘…

Python reversed函数

在Python编程中&#xff0c;reversed()函数是一个内置函数&#xff0c;用于反转序列对象的元素顺序。这个函数可以应用于列表、元组、字符串等可迭代对象&#xff0c;并返回一个反向迭代器&#xff0c;可以按照相反的顺序遍历序列中的元素。本文将深入探讨Python中的reversed()…

Vue学习之计算属性

模板中的表达式虽然方便&#xff0c;但也只能用来做简单的操作。如果在模板中写太多逻辑&#xff0c;会让模板变得臃肿&#xff0c;难以维护。比如说&#xff0c;我们有这样一个包含嵌套数组的对象&#xff1a; const author reactive({name: John Doe,books: [Vue 2 - Advan…

【算法与数据结构】1971、LeetCode寻找图中是否存在路径

文章目录 一、题目二、解法三、完整代码 所有的LeetCode题解索引&#xff0c;可以看这篇文章——【算法和数据结构】LeetCode题解。 一、题目 二、解法 思路分析&#xff1a;本题应用并查集的理论直接就可以解决&#xff1a;【算法与数据结构】回溯算法、贪心算法、动态规划、图…