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

news2024/11/19 4:22:42

目录

前言

一、问题定位

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.coloradmin.cn/o/1466685.html

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

相关文章

项目管理:如何成功完成一个项目

项目管理是一项重要的技能&#xff0c;它可以帮助你成功地完成一个项目。以下是一些关键的步骤&#xff0c;可以帮助你实现这一目标&#xff1a; 1. 明确项目目标&#xff1a;在开始项目之前&#xff0c;你需要明确项目的目标。这将有助于你制定一个明确的计划&#xff0c;并确…

最长公共前缀【简单】

题目 编写一个函数来查找字符串数组中的最长公共前缀。 如果不存在公共前缀&#xff0c;返回空字符串 ""。 示例如下&#xff1a; 所给提示如下&#xff1a; 1 < strs.length < 2000 < strs[i].length < 200strs[i] 仅由小写英文字母组成 解题 根据…

iOS面试:4.多线程GCD

一、多线程基础知识 1.1 什么是进程&#xff1f; 进程是指在系统中正在运行的一个应用程序。对于电脑而已&#xff0c;你打开一个软件&#xff0c;就相当于开启了一个进程。对于手机而已&#xff0c;你打开了一个APP&#xff0c;就相当于开启了一个进程。 1.2 什么是线程&am…

反序列化字符串逃逸 [安洵杯 2019]easy_serialize_php1

打开题目 $_SESSION是访客与整个网站交互过程中一直存在的公有变量 然后看extract()函数的功能&#xff1a; extract($_POST)就是将post的内容作为这个函数的参数。 extract() 函数从数组中将变量导入到当前的符号表(本题的作用是将_SESSION的两个函数变为post传参) function…

MySql-DQL-条件查询

目录 条件查询修改数据 查询 姓名 为 Name10 的员工查询 id小于等于5 的员工信息查询 没有分配职位 的员工信息查询 有职位 的员工信息查询 密码不等于 password1 的员工信息查询 入职日期 在 2000-01-01 (包含) 到 2010-01-01(包含) 之间的员工信息查询 入职时间 在 2000-01-0…

linux之权限管理(实施必会!!!!)

文章目录 一、什么是ACL二、操作步骤2.1. 添加测试目录&#xff0c;用户&#xff0c;组&#xff0c;并将用户添加到组2.2.查看组是否正常建立 cat /etc/group2.3设定权限2.4此时需要为临时用户进行权限&#xff1a; r-x 三、ACL中mask修改最大权限四、ACL权限的删除五、ACL权限…

pclpy KD-Tree K近邻搜索

pclpy KD-Tree K近邻搜索 一、算法原理1.KD-Tree 介绍2.原理 二、代码三、结果1.原点云2.k近邻点搜索后的点云 四、相关数据 一、算法原理 1.KD-Tree 介绍 kd 树或 k 维树是计算机科学中使用的一种数据结构&#xff0c;用于在具有 k 维的空间中组织一定数量的点。它是一个二叉…

MybatisPlus--03--IService、ServiceImpl

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 1. IService接口1.1 IService、ServiceImpl 接口的使用第一步&#xff1a;实现basemapper接口第二步&#xff1a;编写service类第三步&#xff1a;编写serviceImpl第…

【统计分析数学模型】判别分析(三):Bayes判别法

【统计分析数学模型】判别分析&#xff08;三&#xff09;&#xff1a;Bayes判别法 一、Bayes判别法二、R语言实现Bayes判别法1. 运行NaiveBayes()函数2. 绘制密度曲线3. 计算回判正确率 一、Bayes判别法 Bayes判别法假定对研究对象有一定的认识&#xff0c;这种认识用先验概率…

政安晨:【示例演绎机器学习】(四)—— 神经网络的标量回归问题示例 (价格预测)

政安晨的个人主页&#xff1a;政安晨 欢迎 &#x1f44d;点赞✍评论⭐收藏 收录专栏: 政安晨的机器学习笔记 希望政安晨的博客能够对您有所裨益&#xff0c;如有不足之处&#xff0c;欢迎在评论区提出指正&#xff0c;让小伙伴们一起学习、交流进步&#xff0c;不论是学业还是工…

高并发系统实战课个人总结(极客时间)

高并发系统实战课 场景 读多写少 我会以占比最高的“读多写少”系统带你入门&#xff0c;梳理和改造用户中心项目。这类系统的优化工作会聚焦于如何通过缓存分担数据库查询压力&#xff0c;所以我们的学习重点就是做好缓存&#xff0c;包括但不限于数据梳理、做数据缓存、加缓…

FairyGUI × Cocos Creator 3.x 场景切换

前言 前文提要&#xff1a; FariyGUI Cocos Creator 入门 FairyGUI Cocos Creator 3.x 使用方式 个人demo&#xff1a;https://gitcode.net/qq_36286039/fgui_cocos_demo_dust 个人demo可能会更新其他代码&#xff0c;还请读者阅读本文内容&#xff0c;自行理解并实现。 官…

云HIS系统源码,基于云计算技术的B/S架构的云HIS系统,二甲医院信息管理系统

云HIS系统源码&#xff0c;采用云端SaaS服务的方式提供 基于云计算技术的B/S架构的云HIS系统&#xff0c;采用云端SaaS服务的方式提供&#xff0c;使用用户通过浏览器即能访问&#xff0c;无需关注系统的部署、维护、升级等问题&#xff0c;系统充分考虑了模板化、配置化、智能…

邮件发送/接收过程分析、常见邮箱sport/dport列举、检测规则开发思路分析

一、邮件发送和接收过程分析 &#xff08;转载自&#xff1a;邮件的发送和接收过程——STMP、POP、IMAP、MIME_当收件人接收电子邮件时自己的邮件服务器通过什么收文件-CSDN博客&#xff09; 电子邮件发送协议 是一种基于“ 推 ”的协议&#xff0c;主要包括 SMTP &#xff1…

博客 cn 站搭建 v3 v3.1

1. 架构设计 v3.1 版本 2. v2.x 存在的痛点 在v2.x版本中&#xff0c;围绕 服务器 遇到了两个主要的问题&#xff1a; 服务器成本高&#xff1a;博客以静态页面为主&#xff0c;理论上可以实现无服务器部署&#xff0c;但是为了防止恶意攻击&#xff0c;不得不使用服务器进…

RT-Thread-快速入门-3-内存管理

内存管理 定义与作用 内存池管理 基础定义 内存池是一种管理固定大小内存块的机制&#xff0c;主要用于减少碎片化&#xff0c;提高内存分配效率。在 RT-Thread 中&#xff0c;内存池允许用户预分配一定数量的具有相同大小的内存块&#xff0c;应用程序可以从中快速分配和释放内…

【电子书】人工智能

资料 wx&#xff1a;1945423050&#xff0c;备注来源和目的 个人整理了一些互联网电子书 人工智能 Julia机器学习核心编程&#xff1a;人人可用的高性能科学计算.epubKeras深度学习实战.epubMATLAB图像与视频处理实用案例详解.epubMATLAB金融算法分析实战&#xff1a;基于机器…

Android 开发一个耳返程序(录音,实时播放)

本文目录 点击直达 Android 开发一个耳返程序程序编写1. 配置 AndroidManifast.xml2.编写耳返管理器3. 录音权限申请4. 使用注意 最后我还有一句话要说怕相思&#xff0c;已相思&#xff0c;轮到相思没处辞&#xff0c;眉间露一丝 Android 开发一个耳返程序 耳返程序是声音录入…

开源分子对接程序rDock的安装及使用流程

欢迎浏览我的CSND博客&#xff01; Blockbuater_drug …点击进入 前言 本文介绍开源分子对接程序rDock在Linux Ubuntu 22.04系统上的conda安装、编译安装过程及程序使用流程。 一、rDock是什么&#xff1f; rDock来源 rDock是一个快速、多功能的开源对接程序&#xff0c;可用…

鼠标右键助手专业版 MouseBoost PRO for Mac v3.3.6中文破解

MouseBoost Pro mac版是一款简单实用的鼠标右键助手专业版&#xff0c;MouseBoost Pro for Mac只要轻点你的鼠标右键&#xff0c;就可以激活你想要的各种功能&#xff0c;让你的工作效率大幅度提高&#xff0c;非常好用。 软件下载&#xff1a;MouseBoost PRO for Mac v3.3.6中…