Oracle数据库经纬度坐标查询优化与结果错误原因分析、SQL中WKT超长文本字符串处理

news2024/11/16 17:48:18

文章目录

  • 一、Oracle几何空间数据对象和其他数据库的差异
  • 二、Oracle查询一个经纬度坐标是否在边界内部
    • 2.1 查询条件
    • 2.2 查询结果错误,似乎是仅做了MBR匹配
    • 2.3 错误原因
    • 2.4 解决办法
  • 三、SQL中WKT超长文本在Oracle中如何编写
    • 3.1 Oracle中执行含超长文本的SQL报错
    • 3.2 使用CLOB无限拼接得到超长文本
    • 3.3 导入开源的省市区坐标边界WKT数据
  • 四、Oracle数据库的空间索引和查询返回WKT超长文本
    • 4.1 给查询加速:Oracle数据库的空间索引
    • 4.2 如何查询返回SDO_GEOMETRY的WKT超长文本?

一、Oracle几何空间数据对象和其他数据库的差异

和MySQL、PostgreSQL等数据库相比,Oracle数据库的地理几何空间更难学习和上手使用,我总结的一点原因是Oracle Spatial文档中阐述了太多的和其他数据库不通用的几何对象构建、查询方法,需要单独深入学习研究Oracle Spatial文档,知识碎片化严重,实现一个相同功能可能有N个功能相近的函数可以给你调用(茴香豆的茴字的N种写法),学习成本太高,还稍不注意就容易踩坑。

WKT(Well Known Text)是通用的几何空间对象的文本表示方法,相比于同样通用的GeoJSON文本,WKT更简单,易于理解也容易生成,重要的是几乎所有支持地理几何空间的数据库都支持WKT文本。

  • MySQLPostgreSQL中可用ST_GeomFromText('wkt',SRID)来构造几何对象
  • SQLServer中可用geometry::STGeomFromText('wkt',SRID)来构造几何对象
  • Oracle中可用SDO_GEOMETRY('wkt',SRID)来构造几何对象,但此处有坑

SQL语句中手写的单个文本字符串长度,在Oracle中也有限制,测试发现SQLPlus中最长的手写单个文本长度3000左右,SQL Developer中32767左右,超过了长度SQL就没法执行,直接报语法解析错误,这在其他数据库中是闻所未闻的。复杂的一个地理坐标边界图形的WKT可能有上百KB甚至上MB的超长文本,这在Oracle中单纯的使用SQL语句将会是一个很大的挑战。

本地测试所使用的数据库版本:Oracle Database 21c Express Edition Release 21.0.0.0.0
在线测试所使用的Live SQL版本:Live SQL 23.3.1, running Oracle Database 19c EE Extreme Perf - 19.17.0.0.0 (也有坑)
Oracle Spatial参考文档地址:https://docs.oracle.com/en/database/oracle/oracle-database/21/spatl/index.html
开源省市区坐标边界数据(可导入Oracle):https://github.com/xiangyuecn/AreaCity-JsSpider-StatsGov github可换成gitee

二、Oracle查询一个经纬度坐标是否在边界内部

2.1 查询条件

  • 边界几何图形:POLYGON ((53 20, 52 20, 52 23, 57 23, 57 20, 56 20, 56 22, 53 22, 53 20)),类似一个倒过来的凹字
  • 坐标点:POINT (55 21),这个点位于凹进去的里面,但不在凹字内部

边界几何图形和坐标点位置

查询这个坐标点是否在图形内部,结果应当是不在内部。

2.2 查询结果错误,似乎是仅做了MBR匹配

编写查询语句,这里直接给出相同一个图形的顺时针和逆时针两种写法:

declare
	-- 定义坐标点
    p SDO_GEOMETRY:=SDO_GEOMETRY('POINT (55 21)',4326);
	-- 定义边界几何图形(顺时针),如果你的WKT是这种,那放到Oracle里面就惨了
    g1 SDO_GEOMETRY:=SDO_GEOMETRY('POLYGON ((53 20, 52 20, 52 23, 57 23, 57 20, 56 20, 56 22, 53 22, 53 20))',4326);
	-- 定义边界几何图形(逆时针),符合Oracle坐标顺序要求
    g2 SDO_GEOMETRY:=SDO_GEOMETRY('POLYGON ((53 20, 53 22, 56 22, 56 20, 57 20, 57 23, 52 23, 52 20, 53 20))',4326);
    v1 clob; v2 clob;
begin
	-- 计算坐标点和2个边界的位置关系
    select SDO_ANYINTERACT(g1,p),SDO_ANYINTERACT(g2,p) into v1,v2 from dual;
    dbms_output.put_line('g1:'||v1 ||'  '|| 'g2:'||v2);
	
	-- 检查2个边界是否有效(ST_IsValid)
	dbms_output.put_line('g1 IsValid:'||SDO_GEOM.VALIDATE_GEOMETRY_WITH_CONTEXT(g1,0.0000001));
	dbms_output.put_line('g2 IsValid:'||SDO_GEOM.VALIDATE_GEOMETRY_WITH_CONTEXT(g2,0.0000001));
end;

SQL Developer中执行后输出结果(和Live SQL中测试结果相同):

g1:TRUE  g2:FALSE
g1 IsValid:13367 [Element <1>] [Ring <1>]
g2 IsValid:TRUE

可以看到顺时针表示的边界WKT g1 居然包含了这个坐标点:g1:TRUE ;并且检查g1的有效性,显示图形是无效的。

尝试将坐标点改成POINT (55 10),此坐标完全在凹字外面,查询结果就是正确的,因此可以得出:边界g1和坐标p的位置计算只进行了外接矩形(MBR)的匹配,没有进行精确的计算,p坐标点在g1的MBR内部就直接返回了匹配,导致结果错误。

或者去掉SRID(删掉,4326,即SRID=NULL),查询结果也是正确的,这个就很奇葩了,代码正在以奇怪的方式正确运行。。。很有迷惑性。

相同的边界图形WKT 和 坐标点,在MySQL、PostgreSQL、SQLServer中测试均结果正确,也不存在图形无效的问题,仅仅是Oracle上有问题。

2.3 错误原因

这个错误结果困扰了一个多礼拜,SDO_ANYINTERACTSDO_RELATE的文档中没有找到关于图形坐标方向的说明,一度以为是提供了SRID的问题(只因SRID=NULL时查询结果又是正确的),还好后面在 SDO_ELEM_INFO 和 Recommendations for Loading and Validating Spatial Data文档中得到了确切的答案:

You should specify 3 only if you do not know if the simple polygon is exterior or interior, and you should then upgrade the table or layer to the current format using the SDO_MIGRATE.TO_CURRENT procedure, described in SDO_MIGRATE Package (Upgrading) .

1005: exterior polygon ring (must be specified in counterclockwise order)
2005: interior polygon ring (must be specified in clockwise order)

For any geometries with the wrong orientation or an invalid ETYPE or GTYPE value, use SDO_MIGRATE.TO_CURRENT on these invalid geometries to fix them.

意思就是Oracle里面边界图形的外环必须逆时针的。但SDO_ANYINTERACT查询的时候,对于顺时针的错误图形,Oracle既不报错还返回错误结果,这就很离谱,这点的原因还没翻到文档说明。注:其他几个数据库并不要求环的方向顺序。

2.4 解决办法

根据文档提示,使用 SDO_MIGRATE.TO_CURRENT 方法对SDO_GEOMETRY构造出来的边界几何图形坐标的顺序进行处理,达到方向顺序要求

	-- 在原来的基础上,套一层TO_CURRENT()调用,提供一个dim数组即可
    g1 SDO_GEOMETRY:=SDO_MIGRATE.TO_CURRENT(SDO_GEOMETRY('POLYGON ((53 20, 52 20, 52 23, 57 23, 57 20, 56 20, 56 22, 53 22, 53 20))',4326),SDO_DIM_ARRAY(SDO_DIM_ELEMENT('X', -180, 180, 0.0000001),SDO_DIM_ELEMENT('Y', -90, 90, 0.0000001)));

套了一层TO_CURRENT()后,对g1的查询就对了,图形的有效性也是正确的。

三、SQL中WKT超长文本在Oracle中如何编写

3.1 Oracle中执行含超长文本的SQL报错

修改并运行以下代码:

-- 字符串里面放50k的字符串,可浏览器控制台里面执行js得到长文本: new Array(50001).join("a")
select '这里放50000个字符......' from dual;

SQL Developer 中直接报错(Live SQL支持更差):

ORA-01704: 字符串文字太长
01704. 00000 -  "string literal too long"
*Cause:    The string literal is longer than 4000 characters.
*Action:   Use a string literal of at most 4000 characters.
           Longer values may only be entered using bind variables.

好家伙,第一次见限制SQL语句中字符串长度的,翻阅文档找到了 PL/SQL Program Limits,size of a string literal (bytes): 32767,其他数据库从来没有这种问题。Longer values may only be entered using bind variables.提示的这个解决办法目测是针对编程环境下的PreparedStatement,我都写SQL了,SQL文件里面绑个锤子的变量。

开头也说过了复杂地理坐标边界图形的WKT可能有上百KB甚至几MB的超长文本,其他数据库直接简单的通过类似insert tab values('100kb wkt')即可完成插入,现在Oracle由于这个书写字符串长度的限制,势必要额外编写非常规的代码。

3.2 使用CLOB无限拼接得到超长文本

Oracle的CLOB类型能放下4GB的文本,因此可以将超长的WKT文本切分成一小段一小段的文本,拼接进clob变量里面,避免单个字符串过长,即可解决这个问题。

declare txt clob:='';begin
	txt:=txt||'POLYGON(( .... WKT切分的2KB字符串';
	txt:=txt||'.... WKT切分的2KB字符串';
	txt:=txt||'.... WKT切分的2KB字符串';
	-- ...... 剩余的2KB字符串
	
	dbms_output.put_line('txt: '||dbms_lob.getlength(txt));
	
	-- 把超长WKT文本转成几何空间对象,修正坐标方向,插入数据库
	-- INSERT INTO tableName(polygon) VALUES( SDO_MIGRATE.TO_CURRENT(SDO_GEOMETRY(txt,4326),SDO_DIM_ARRAY(SDO_DIM_ELEMENT('X', -180, 180, 0.0000001),SDO_DIM_ELEMENT('Y', -90, 90, 0.0000001))) );
end;
/

Oracle不同终端(SQLPlus、SQL Developer)里面SQL能书写的单个字符串长度混乱,3k-32k不等,因此长字符串采取2KB长度分段拼接进行支持,获得最大兼容;CLOB直接用||拼接即可,无需使用to_clobdbms_lob.append

注意:Live SQL中测试时,如果SQL语句的总长度超过32KB(非单个字符串),查询将会报错,或不压根返回结果,和SQLPlus、SQL Developer表现的完全不一样;可以理解为目前Live SQL中无法进行携带任何超长文本的测试。

3.3 导入开源的省市区坐标边界WKT数据

从开源库:AreaCity-JsSpider-StatsGov 里面的文档中获取到最新的省市区三级或乡镇级数据,有shp、geojson、sql格式支持,只需选择导出Oracle格式的SQL文件即可,在SQLPlus、或SQL Developer里面执行这个SQL文件即可完成导入:

@"D:/xxx/xxx.sql"; --改成实际的文件路径

SQL文件中的超长WKT文本按照上面2KB一段的长度进行了切分,使用CLOB拼接。此SQL文件结尾会自动创建索引,或者根据下文手动创建索引,建了索引后 SDO_ANYINTERACT 查询速度快100倍。

四、Oracle数据库的空间索引和查询返回WKT超长文本

4.1 给查询加速:Oracle数据库的空间索引

空间索引文档:Indexing and Querying Spatial Data,涉及user_sdo_geom_metadata这个表,这个表很重要,虽然里面只存了经纬度范围和SRID!

如果user_sdo_geom_metadata里面配置的SRID和导入到表里的数据SRID不一致,将会导致空间查询时直接报错。数据的SRID=NULL时,metadata里面的SRID也必须是NULL,其他SRID必须是一个存在的SRID值(通过 select * from MDSYS.CS_SRS order by srid 查询所有SRID)。

然后创建正常创建索引即可:

-- 先往user_sdo_geom_metadata里面插入配置数据
insert into user_sdo_geom_metadata(TABLE_NAME,COLUMN_NAME,DIMINFO,SRID)VALUES (upper('tableName'),upper('polygon'),SDO_DIM_ARRAY(SDO_DIM_ELEMENT('X', -180, 180, 0.0000001),SDO_DIM_ELEMENT('Y', -90, 90, 0.0000001)),NULL); -- SRID=NULL 或 一个具体值

-- 创建空间索引
create index indexName ON tableName(polygon) INDEXTYPE IS MDSYS.SPATIAL_INDEX_V2;

测试发现:修改表名会自动修改metadata里面的表名,删除表不会删除metadata里面的此表的相关配置。

表中空间数据量比较多的时候,加空间索引对查询速度的优化效果非常明细,上面导入的省市区三级的边界数据3600多条,不加索引时要7秒查询一个坐标,加了索引后只需0.06秒查询一次,查询性能提高了100倍。

4.2 如何查询返回SDO_GEOMETRY的WKT超长文本?

超长的WKT文本通过CLOB拼接的SQL语句插入数据库后,仅通过SQL查询语句从边界几何对象中读取出WKT文本似乎又是一个难题。

select SDO_GEOMETRY.GET_WKT(polygon) from tableName;

GET_WKT方法经常动不动就报错(偶尔又能正常查出来):

ORA-13199: wk buffer merge failure
ORA-06512: 在 "MDSYS.SDO_UTIL", line 857
ORA-06512: 在 "MDSYS.SDO_UTIL", line 896
ORA-06512: 在 "MDSYS.SDO_GEOMETRY", line 36

目前暂无办法稳定的查询出SDO_GEOMETRY的WKT超长文本,Oracle难搞哦。

注:以上问题(疑难杂症)MySQL、PostgreSQL、SQLServer 均无,这样说,你应该知道怎么选了吧=。=

【完】

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

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

相关文章

健身耳机哪个牌子好?推荐几款最适合健身运动用的耳机牌子

对于健身爱好者来说&#xff0c;选择一款适合健身运动的耳机是至关重要的&#xff0c;无论你是跑步、举重还是瑜伽&#xff0c;有适合自己的耳机戴着听歌&#xff0c;能够让你更加投入、更加享受健身的过程。可现在如今的耳机品牌琳琅满目&#xff0c;在选择上自然是要花上不少…

搭建Everything+cpolar在线资料库,实现随时随地访问

Everythingcpolar搭建在线资料库&#xff0c;实现随时随地访问 文章目录 Everythingcpolar搭建在线资料库&#xff0c;实现随时随地访问前言1.软件安装完成后&#xff0c;打开Everything2.登录cpolar官网 设置空白数据隧道3.将空白数据隧道与本地Everything软件结合起来总结 前…

山西电力市场日前价格预测【2023-08-22】

日前价格预测 预测明日&#xff08;2023-08-22&#xff09;山西电力市场全天平均日前电价为313.08元/MWh。其中&#xff0c;最高日前电价为354.58元/MWh&#xff0c;预计出现在18: 45。最低日前电价为271.10元/MWh&#xff0c;预计出现在12: 30。 价差方向预测 1&#xff1a; 实…

CrossOver2023虚拟机工具最新版本功能介绍

想要在Mac OS中运行Windows程序&#xff0c;除了使用虚拟机外&#xff0c;使用CrossOver在Mac OS系统中运行Windows程序是非常不错的选择。CrossOver基于Wine技术&#xff0c;可以在Mac OS上运行许多Windows应用程序&#xff0c;而无需安装整个Windows操作系统。 本次发布的Cr…

Paraverse平行云入选启元计划元宇宙TOP20榜单

近日&#xff0c;2023全球数字经济大会互联网3.0峰会上&#xff0c;由中关村大数据产业联盟、中国科协科技传播中心、北京信息化协会共同发起的启元计划发布其成果&#xff0c;同时公布启元计划TOP20以及TOP50企业入选名单。凭借技术与生态优势&#xff0c;「Paraverse平行云」…

docker 05(dockerfile)

一、docker镜像原理 镜像可以复用 二、容器转镜像 将容器保存为镜像[参考] docker commit -a -m 现有容器ID 保存后的名称&#xff1a;版本号 -a :提交的镜像作者&#xff1b; -c :使用Dockerfile指令来创建镜像&#xff1b; -m :提交时的说明文字&#xff1b; -p :…

常用字符串匹配算法

一、BF匹配 BF算法中的BF是Brute Force的缩写&#xff0c;中文叫作暴力匹配算法&#xff0c;也叫朴素匹配算法。 BF算法的时间复杂度很高&#xff0c;是O(nm)&#xff0c;但在实际的开发中&#xff0c;它却是一个比较常用的字符串匹配算法。 第一&#xff0c;实际的软件开发中…

网络安全(黑客)自学笔记建议

前言 1.不要试图以编程为基础的学习开始学习 我在之前的回答中&#xff0c;我都一再强调不要以编程为基础再开始学习网络安全&#xff0c;一般来说&#xff0c;学习编程不但学习周期长&#xff0c;而且实际向安全过渡后可用到的关键知识并不多 一般人如果想要把编程学好再开…

安防视频监控平台EasyCVR视频集中存储平台接入RTSP设备出现离线情况的问题解决方案

安防视频监控/视频集中存储/云存储/磁盘阵列EasyCVR平台可拓展性强、视频能力灵活、部署轻快&#xff0c;可支持的主流标准协议有国标GB28181、RTSP/Onvif、RTMP等&#xff0c;以及支持厂家私有协议与SDK接入&#xff0c;包括海康Ehome、海大宇等设备的SDK等。平台既具备传统安…

Web Worker的使用

Web Worker 前言一、Web Worker是什么&#xff1f;二、使用步骤2.1 创建 Web Worker2.2 监听消息2.3 发送消息 三、优点与缺点3.1 优点3.2 缺点 总结 前言 JavaScript采用的是单线程模型&#xff0c;也就是说&#xff0c;所有任务只能在一个线程上完成&#xff0c;一次只能做一…

【leetcode 力扣刷题】 两数/三数/四数之和 哈希表和双指针解题

两数/三数/四数之和 题目合集 哈希表求解1. 两数之和454. 四数相加Ⅱ 双指针求解15.三数之和18. 四数之和 这个博客是关于&#xff1a;找出数组中几个元素&#xff0c;使其之和等于题意给出的target 这一类题目的&#xff0c;但是各个题之间又有些差异&#xff0c;使得需要用不…

lwIP更新记10:IP 冲突检测

lwip-2.2.0-rc1 版本于 2023 年 6 月 29 日发布&#xff0c;带来了我期盼已久的 IPv4 冲突检测 功能。 lwip-2.2.0-rc1 版本重新回归了 master 分支&#xff08;主分支&#xff09;&#xff0c;不再使用单独的稳定分支。 master 分支 是一个 Git&#xff08;版本控制程序&…

C#8.0本质论第四章--操作符和控制流程

C#8.0本质论第四章–操作符和控制流程 4.1操作符 有些操作符以符号的形式出现&#xff0c;例如、-、?.或者??等&#xff0c;而另一些操作符则为关键词&#xff0c;例如default和is。 4.1.1一元正负操作符 一元正操作符()对值几乎没有影响&#xff0c;它在C#中是多余的。…

python 连接Redis 数据库

pip install redis python代码 import redis# 连接数据库 r redis.Redis(host192.168.56.15, port6379, db0)# 存储数据 #r.set(key, value) r.set(name, zaraNet)# 获取数据 value r.get(name) print(value)# 关闭连接&#xff08;可选&#xff09; r.close()

AP9196 DC-DC 升压 升降压 恒流电源管理芯 LED电源驱动IC

产品说明 AP9196 是一系列外围电路简洁的宽调光比升压调光恒流驱动器&#xff0c;适用于 3-40V 输入电压范围的 LED照明领域。AP9196 采用我司专利算法&#xff0c;可以实现高精度的恒流效果&#xff0c;输出电流恒流精度≤3&#xff05;&#xff0c;电压工作范围为5-40V&…

Redis 缓存满了怎么办?

引言 Redis 缓存使用内存来保存数据&#xff0c;随着需要缓存的数据量越来越大&#xff0c;有限的缓存空间不可避免地会被写满。此时&#xff0c;应该怎么办&#xff1f;本篇文章接下来就来聊聊缓存满了之后的数据淘汰机制。 值得注意的是&#xff0c;在 Redis 中 过期策略 和…

【rar密码】rar压缩包密码列表

之前给大家介绍过WinRAR自动加密的设置方法&#xff0c;今天再介绍一种RAR压缩包加密方法&#xff1a;整理密码。 什么是整理密码&#xff1a; 在加密rar文件的时候&#xff0c;点击下拉框选择密码&#xff0c;不用输入密码 设置方法&#xff1a; 前面的操作步骤和设置自动…

正中优配:尾盘拉升的股票第二天的走势?

尾盘拉升是指买卖日快结束时股票价格呈现上涨的状况。关于许多投资者来说&#xff0c;这一般是好事情&#xff0c;因为它可认为他们带来更高的收益。但是&#xff0c;人们常常会问尾盘拉升的股票第二天的走势怎么。本文将从多个角度进行剖析。 首要&#xff0c;咱们需求认识到这…

这所211太好考了!263分上岸!平均分300分!

一、学校及专业介绍 宁夏大学&#xff08;Ningxia University&#xff0c;简称&#xff1a;宁大&#xff09;&#xff0c;是中国教育部与宁夏回族自治区人民政府合建高校&#xff0c;位列国家“双一流”“211工程”重点建设高校&#xff0c;国家“中西部高校综合实力提升工程”…

cpolar+JuiceSSH实现手机端远程连接Linux服务器

文章目录 1. Linux安装cpolar2. 创建公网SSH连接地址3. JuiceSSH公网远程连接4. 固定连接SSH公网地址5. SSH固定地址连接测试 处于内网的虚拟机如何被外网访问呢?如何手机就能访问虚拟机呢? cpolarJuiceSSH 实现手机端远程连接Linux虚拟机(内网穿透,手机端连接Linux虚拟机) …