# 基于网格编码的多图层穿越查询 在海量空间数据管理系统中,经常需要多图层查询的应用,比如查看指定范围内有哪些图层,各图层在此区域大约有多少对象,并获取属性相关的统计数据。 传统的实现方式是对所有图层逐个进行范围过滤,尽管各图层有空间索引进行加速,随着图层数量的增加,仍无法满足实时或近实时的查询效果。 面向网格的空间数据管理方式,能够很好地解决这个问题。本文详细说明其使用过程。 ## 基本原理 该使用场景的基本原理:对原始数据的各图层对象进行编码,保留对象 ID 和网格,汇总到一张网格编码表中,示例如下: ```{image} ../../../_static/images/demo_geosot/5.geosot2-grids-schema.png :width: 600px :alt: 网格编码表结构 ``` **查询过程**: 1. 计算查询对象所压盖的网格; 2. 计算出的网格数组与网格编码表的网格数组列进行求交(`&&` 操作符),有相同网格的行被命中; 3. 命中的行再与原始数据做 ID 关联,得到最终查询结果。 ## 脚本及过程说明 ```sql -- 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; ``` ## 总结 本例提供的基于网格编码的多图层穿越查询方法,不影响原始数据,提供高效检索性能的同时,也适用于对只读的存量数据管理。