如何在PostGIS中利用索引实现PointZM类型时空点的高效查询
Absolutely! You can absolutely leverage your existing GIST index to perform combined spatial-temporal queries in PostGIS 2.3.2 with PostgreSQL 9.6—you just need to use the right 4D operators instead of the 3D ones you're currently using.
The Root of Your Issue
The problem with your current query is that the &&& operator only checks the X/Y/Z dimensions of your PointZM geometry. The M-value (which stores your timestamp) isn't considered by this 3D operator, which is why your index only filters on spatial dimensions, forcing you to add a separate st_m() filter that runs after the index scan.
Solution: Use 4D Spatial Operators
PostGIS provides a 4D spatial operator (&&&&) that compares all four dimensions of a PointZM (X/Y/Z/M), plus a function to create a 4D bounding box (ST_MakeBox4D). Here's how to rewrite your query to use these tools:
SELECT * FROM huge_spatial_table WHERE timegeom &&&& ST_MakeBox4D( ST_SetSRID(ST_MakePoint(0.05278027, 29.47846469, 0, date_part('epoch', '2013-01-01'::timestamp)), 4326), ST_SetSRID(ST_MakePoint(37.50180758, 45.37019107, -50, date_part('epoch', '2018-01-01'::timestamp)), 4326) );
Why This Works
Your existing GIST(timegeom gist_geometry_ops_nd) index is already compatible with 4D queries—gist_geometry_ops_nd is designed for N-dimensional spatial data, including 4D PointZM. The &&&& operator will use this index to filter records that fall within the 4D bounding box you define, covering both your spatial bounds (X/Y/Z) and temporal bounds (M/timestamp) in a single index scan.
For Open-Ended Ranges
If you need open-ended ranges (e.g., st_m(timegeom) > ... instead of >=), you can still add those conditions. However, the index will already have narrowed down the result set to a tiny subset, making the post-filter extremely fast.
Verify the Execution Plan
Run EXPLAIN ANALYZE on the rewritten query to confirm it's using the index for both spatial and temporal filtering. You should see the index scan directly uses the 4D bounding box condition, with no need for a separate M-value filter unless you're using open ranges.
Alternative: Composite Index (If Needed)
If for some reason the 4D operator doesn't work in your environment (though it should in PostGIS 2.3+), you can split your timestamp into a separate column and create a composite GIST index:
-- Add a separate column for the timestamp epoch ALTER TABLE huge_spatial_table ADD COLUMN timestamp_epoch double precision; UPDATE huge_spatial_table SET timestamp_epoch = st_m(timegeom); -- Create composite spatial-temporal index CREATE INDEX idx_huge_spatial_table_spatial_temporal ON huge_spatial_table USING GIST(timegeom, timestamp_epoch);
Then query with:
SELECT * FROM huge_spatial_table WHERE timegeom &&& ST_3DMakeBox( ST_SetSRID(ST_MakePoint(0.05278027,29.47846469,0),4326), ST_SetSRID(ST_MakePoint(37.50180758,45.37019107,-50),4326) ) AND timestamp_epoch BETWEEN date_part('epoch', '2013-01-01'::timestamp) AND date_part('epoch', '2018-01-01'::timestamp);
This adds extra storage and maintenance overhead though, so using the 4D operator is the cleaner approach.
内容的提问来源于stack exchange,提问作者kau

