All Products
Search
Document Center

PolarDB:Geographic grid model

Last Updated:Mar 28, 2026

GanosBase GeomGrid is a spatio-temporal extension for PolarDB for PostgreSQL that lets you store, query, and analyze geographic grids directly in the database. It supports two industry-standard grid systems — GeoSOT and H3 — and provides spatial operations, relationship identification, and index types optimized for grid data.

Key concepts

Geographic grid model

A geographic grid model divides the Earth's surface into hierarchical, regularly shaped cells. Each cell has a unique code, turning continuous geographic space into discrete, addressable units. This makes it practical to associate spatial data with grid cells, run proximity queries, and aggregate results at any precision level.

GeoSOT

GeoSOT is a Chinese-developed Earth subdivision theory based on quad-tree projection. It expands the Earth's surface from 180°×360° to a 512°×512° plane and recursively subdivides that plane to level 32, producing grids that range from the full globe down to a few centimeters. Each cell is encoded as a quaternary number of up to 32 bits. The encoding interleaves latitude and longitude into a 62-bit Morton code, prefixed with a hemisphere indicator (G0 = northeast, G1 = northwest, G2 = southeast, G3 = southwest).

GeoSOT supports a 3D extension: the height dimension is subdivided consistently with longitude and latitude. Each height grid corresponds to a 1° ground surface grid, adding 256 levels above ground and 256 levels below.

H3

H3 is a two-dimensional geographic grid that projects the Earth onto a sphere-circumscribed icosahedron (20 triangular faces, 12 vertices), then covers each face with hexagonal cells. This yields 122 base cells, each recursively divided into 7 finer cells. H3 codes are up to 63 bits and are typically serialized as hexadecimal strings.

GeomGrid and H3Grid

GeomGrid is the GanosBase data type for GeoSOT grids. H3Grid is the data type for H3 grids. Both types support import from and export to other GanosBase types (Text, Bytea, Geometry, Meshgeom, Sfmesh, Vomesh).

Choose between GeoSOT and H3

DimensionGeoSOTH3
Cell shapePolygon (quad-tree subdivision)Hexagon
Max precisionLevel 32 (~centimeter)Higher resolutions support finer precision
3D supportYes (height dimension: 256 levels above and below ground)No
EncodingQuaternary Morton code (up to 32 bits)63-bit integer, hex string
SubdivisionEach cell divides into 4 child cellsEach cell divides into 7 child cells
Typical usePath planning, 3D UAV (unmanned aerial vehicle) routingAggregation, heatmaps

GeoSOT precision levels

The grid level determines cell size. Use this table to select the level that matches your precision requirement.

LevelGrid dimensionExample use
1–9Degree-levelCountry or province-scale queries
10–15Minute-levelCity or district-scale queries
16–21Second-levelStreet or building-level queries
22–32Sub-second (down to ~centimeter)High-precision location

Use cases

Grid query

Convert a point or area into a grid code and query which stored grid codes intersect or contain it. Supports degenerated grids and parent/child node traversal.

Example: When a shared bicycle is parked, convert the GPS position to a grid code, then query the database to find the nearest designated parking area.

Grid aggregation

Aggregate trajectory data — such as ship or vehicle paths — into grid cells to build heatmaps or population distribution maps. The trajectory points are converted to grid codes, and the count of points per cell becomes the heat value.

Grid aggregation heatmap

Grid pathfinding

Use 3D GeoSOT grids to plan routes in complex environments, such as UAV flight paths. Assign traversal costs to obstacle cells, then apply a pathfinding algorithm to find the optimal path.

Grid pathfinding for UAV routing

How indexes work

Without an index, a spatial query scans every row in the table. For large datasets, this is prohibitively slow. GanosBase GeomGrid supports three index types:

IndexHow it worksWhen to use it
B-treeCompares grid codes as ordered valuesEquality and range queries on a single grid column
GiSTR-tree structure over bounding boxes; filters candidates with a fast box test, then verifies each candidate with an exact spatial checkIntersection and containment queries on GeomGrid
GridGinExtends PostgreSQL GIN; indexes individual grid codes within array columnsGrid array queries, degenerated grid queries, grid aggregation

GiST and GridGin use a two-phase approach: the index first identifies candidate rows using bounding boxes, then the database verifies each candidate with a precise spatial test. This avoids scanning the full table while keeping results exact.

Index selection guide

  • Use GridGin for grid array columns (geomgrid[]) — it supports degenerated grid queries and accelerates aggregation.

  • Use GiST for single GeomGrid columns where you need intersection or containment queries.

  • Use B-tree for equality lookups or sorting on grid code values.

Quick start

Prerequisites

Before you begin, make sure you have:

  • A PolarDB for PostgreSQL cluster

  • Database access with permission to create extensions

GeoSOT grid operations

  1. Create the extension in the public schema to avoid permission issues.

    If the command fails with an error about a missing dependent extension such as ganos_sfmesh, contact us.
    CREATE EXTENSION Ganos_GeomGrid WITH SCHEMA public CASCADE;
  2. Create a table with geometry and grid code columns.

    -- Table with geometry source and multi-precision grid columns.
    CREATE TABLE t_grid (
      id    integer,
      geom  geometry,    -- Source geometry
      grid1 geomgrid[],  -- Grid codes at precision level 10
      grid2 geomgrid[],  -- Grid codes at precision level 15
      grid3 geomgrid[]   -- Grid codes at precision level 26
    );
  3. Insert geometry data.

    -- Insert point data.
    INSERT INTO t_grid (id, geom)
    VALUES
      (1, ST_GeomFromText('POINT(116.31522216796875 39.910277777777778)', 4490)),
      (2, ST_GeomFromText('POINT(116.31522217796875 39.910277776777778)', 4490)),
      (3, ST_GeomFromText('POINT(116.31522217797875 39.910277776787778)', 4490)),
      (4, ST_GeomFromText('POINT(116.31522227796875 39.910277776775778)', 4490));
    
    -- Insert polygon data.
    INSERT INTO t_grid (id, geom)
    VALUES (5, 'SRID=4490;POLYGON((-0.08077 -0.02814, 0.0482 -0.03, 0.07426 0.03724, -0.08077 -0.02814))'::geometry);
    
    -- Insert 3D arc data.
    INSERT INTO t_grid (id, geom)
    VALUES (6, 'SRID=4490;CIRCULARSTRING Z (-63.597471 44.8071 20,-63.597 44.807 0,-63.5974 44.807 40)'::geometry);
  4. Calculate grid codes at different precision levels.

    -- Populate grid codes at three precision levels.
    UPDATE t_grid
    SET grid1 = ST_AsGrid(geom, 10),
        grid2 = ST_AsGrid(geom, 15),
        grid3 = ST_AsGrid(geom, 26);
    
    -- Calculate a degenerated grid code for a polygon (id = 5).
    UPDATE t_grid SET grid1 = ST_AsGrid(geom, 18, true) WHERE id = 5;
    
    -- Calculate a 3D grid code (id = 6).
    UPDATE t_grid SET grid1 = ST_As3DGrid(geom, 25) WHERE id = 6;
  5. Create GIN indexes on each grid column to accelerate queries.

    CREATE INDEX idx_grid_gin1 ON t_grid USING GIN (grid1);
    CREATE INDEX idx_grid_gin2 ON t_grid USING GIN (grid2);
    CREATE INDEX idx_grid_gin3 ON t_grid USING GIN (grid3);
  6. Query the grid data. All examples use array operators with the indexed grid columns.

    -- Find rows whose grid2 codes are contained in a specific grid.
    SELECT id FROM t_grid
    WHERE grid2 = ARRAY[ST_GridFromText('G001310322230230')];
    
    -- Find rows whose grid3 codes intersect with a specific grid.
    SELECT id FROM t_grid
    WHERE grid3 @> ARRAY[ST_GridFromText('G00131032223023031031033223')];
    
    -- Find rows whose grid3 codes intersect with any of multiple grids.
    SELECT id FROM t_grid
    WHERE grid3 && ARRAY[
      ST_GridFromText('G00131032223023031031211001'),
      ST_GridFromText('G00131032223023031031211111')
    ];
    
    -- Find rows whose grid3 codes intersect with the grid coverage of a line.
    SELECT id FROM t_grid
    WHERE grid3 &&
      ST_AsGrid(
        ST_GeomFromText('LINESTRING(116.31522216796875 39.910277777777778, 116.31522217797875 39.910277776787778)', 4490),
        26
      );

H3 grid operations

  1. Create a table with an H3 grid column.

    CREATE TABLE h3_grid (
      id   integer,
      geom geometry,   -- Source geometry
      h3   h3grid[]    -- H3 grid codes
    );
  2. Insert geometry data.

    INSERT INTO h3_grid VALUES (1, 'POINT(102.5 25.7)'::geometry);
    INSERT INTO h3_grid VALUES (2, 'POLYGON((-0.08077 -0.02814, 0.0482 -0.03, 0.07426 0.03724, -0.08077 -0.02814))'::geometry);
  3. Calculate H3 grid codes.

    -- Regular H3 grid codes at resolution level 7.
    UPDATE h3_grid SET h3 = ST_AsH3Grid(geom, 7);
    
    -- Degenerated H3 grid codes at resolution level 7.
    UPDATE h3_grid SET h3 = ST_AsH3Grid(geom, 7, true);
  4. Create a B-tree index on the H3 column.

    CREATE INDEX h3_grid_btree ON h3_grid (h3);
  5. Query the H3 data.

    -- Display H3 codes as text.
    SELECT ST_AsText(h3[1]) FROM h3_grid;
    
    -- Query rows with H3 codes greater than a reference value.
    SELECT * FROM h3_grid WHERE h3 > ARRAY[ST_H3FromText('884a126689fffff')];

Remove the extension

Run the following command to remove GanosBase GeomGrid and its dependent objects.

DROP EXTENSION Ganos_GeomGrid CASCADE;

What's next

  • GeomGrid SQL reference — Full function reference for GeomGrid spatial operations, type conversions, and relationship functions