基于网格编码的多图层穿越查询
在海量空间数据管理系统中,经常需要多图层查询的应用,比如查看指定范围内有哪些图层,各图层在此区域大约有多少对象,并获取属性相关的统计数据。
传统的实现方式是对所有图层逐个进行范围过滤,尽管各图层有空间索引进行加速,随着图层数量的增加,仍无法满足实时或近实时的查询效果。
面向网格的空间数据管理方式,能够很好地解决这个问题。本文详细说明其使用过程。
基本原理
该使用场景的基本原理:对原始数据的各图层对象进行编码,保留对象 ID 和网格,汇总到一张网格编码表中,示例如下:
查询过程:
计算查询对象所压盖的网格;
计算出的网格数组与网格编码表的网格数组列进行求交(
&&操作符),有相同网格的行被命中;命中的行再与原始数据做 ID 关联,得到最终查询结果。
脚本及过程说明
-- 1. 创建网格编码表格 tb_geogrid
------ 1.1 创建自增序列对象
CREATE SEQUENCE public.tb_geogrid_id_seq
INCREMENT BY 1 MINVALUE 1 MAXVALUE 2147483647 START 1 CACHE 1 NO CYCLE;
------ 1.2 创建表格 tb_geogrid,编码值将存储在 grids_level_15 列
CREATE TABLE public.tb_geogrid (
id INT4 NOT NULL DEFAULT nextval('tb_geogrid_id_seq'::regclass),
tablename TEXT NULL,
smid INT8 NULL,
grids_level_15 _geosotgrid NULL
);
-- 2. 各图层对象编码计算并数据写入 tb_geogrid 表的 grids_level_15 列,15 层编码;
-- 图层名以 xxx 示意
------ 注意:ST_GeoSOTGrid(smgeometry, 15) 中,smgeometry 是否带 Z 值,
-- 决定了生成的网格是否带 Z 值;同一列中的网格必须具有相同层级和 Z 方向标记
INSERT INTO tb_geogrid (tablename, smid, grids_level_15)
SELECT 'xxx', smid, ST_GeoSOTGrid(smgeometry, 15)
FROM xxx;
-- 3. 为 tb_geogrid 表的 grids_level_15 列创建 GIN 索引
CREATE INDEX idx_tb_geogrid_grids
ON public.tb_geogrid USING GIN (grids_level_15);
-- 4. 查询过滤:指定范围与网格编码表求交,按图层分组统计
SELECT tablename, COUNT(*)
FROM tb_geogrid
WHERE grids_level_15 && ST_GeoSOTGrid(
ST_MakeEnvelope(116.4, 40, 116.45, 40.05, 4490), 22
)
GROUP BY tablename;
总结
本例提供的基于网格编码的多图层穿越查询方法,不影响原始数据,提供高效检索性能的同时,也适用于对只读的存量数据管理。