【问题标题】:How to query space-time points with index in PostGIS如何在 PostGIS 中使用索引查询时空点
【发布时间】:2021-08-26 13:01:52
【问题描述】:

我用 PointZM(经度、纬度、深度、时间纪元)几何列存储了数百万个点

ST_SetSRID(st_makepoint(longitude,latitude,-z,date_part('epoch', "timestamp"::timestamp)),4326) as timegeom

我在列上创建了一个GIST(geometry gist_geometry_ops_nd) 索引

现在,如何在空间和时间上查询这个?

我尝试过使用 &&& 运算符:

select * from huge_spatial_table 
where timegeom &&& st_3dmakebox(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)) 

但是这样做时没有过滤时间维度。

当使用 st_m(geometry) 过滤时间时,它可以工作,但索引没有用于我想要的时间维度。

select * from huge_spatial_table 
where timegeom &&& st_3dmakebox(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)) 
and st_m(timegeom)>date_part('epoch', '2013-01-01'::timestamp)
and st_m(timegeom)<date_part('epoch', '2018-01-01'::timestamp)

解释:

"Index Scan using idx_huge_spatial_table  on huge_spatial_table   (cost=0.55..2.78 rows=1 width=184)"
"  Index Cond: (timegeom &&& '010F0000A0E6100000060000000103000080010000000500000045500CFB0306AB3F3DD773A97C7A3D40000000000000000045500CFB0306AB3FEB75C56B62AF46400000000000000000117E143B3BC04240EB75C56B62AF46400000000000000000117E143B3BC042403DD773A97C7A3D40000000000000000045500CFB0306AB3F3DD773A97C7A3D4000000000000000000103000080010000000500000045500CFB0306AB3F3DD773A97C7A3D4000000000000049C0117E143B3BC042403DD773A97C7A3D4000000000000049C0117E143B3BC04240EB75C56B62AF464000000000000049C045500CFB0306AB3FEB75C56B62AF464000000000000049C045500CFB0306AB3F3DD773A97C7A3D4000000000000049C00103000080010000000500000045500CFB0306AB3F3DD773A97C7A3D40000000000000000045500CFB0306AB3F3DD773A97C7A3D4000000000000049C045500CFB0306AB3FEB75C56B62AF464000000000000049C045500CFB0306AB3FEB75C56B62AF4640000000000000000045500CFB0306AB3F3DD773A97C7A3D40000000000000000001030000800100000005000000117E143B3BC042403DD773A97C7A3D400000000000000000117E143B3BC04240EB75C56B62AF46400000000000000000117E143B3BC04240EB75C56B62AF464000000000000049C0117E143B3BC042403DD773A97C7A3D4000000000000049C0117E143B3BC042403DD773A97C7A3D4000000000000000000103000080010000000500000045500CFB0306AB3F3DD773A97C7A3D400000000000000000117E143B3BC042403DD773A97C7A3D400000000000000000117E143B3BC042403DD773A97C7A3D4000000000000049C045500CFB0306AB3F3DD773A97C7A3D4000000000000049C045500CFB0306AB3F3DD773A97C7A3D4000000000000000000103000080010000000500000045500CFB0306AB3FEB75C56B62AF4640000000000000000045500CFB0306AB3FEB75C56B62AF464000000000000049C0117E143B3BC04240EB75C56B62AF464000000000000049C0117E143B3BC04240EB75C56B62AF4640000000000000000045500CFB0306AB3FEB75C56B62AF46400000000000000000'::geometry)"
"  Filter: ((st_m(timegeom) > '1356998400'::double precision) AND (st_m(timegeom) < '1514764800'::double precision))"

是否甚至可以使用 PostGIS 中的索引进行时空查询?

顺便说一句,我使用的是 postgres 9.6 和 PostGIS 2.3.2

【问题讨论】:

    标签: sql postgresql postgis


    【解决方案1】:

    欢迎来到 SO。

    您可以创建一个额外的索引,其中仅包含几何的 M 维度,例如这将缩短查询时间:

    CREATE INDEX idx_t_geom_m ON huge_spatial_table (ST_M(geom));
    
    不带索引的查询计划(100k随机点):
    Bitmap Heap Scan on huge_spatial_table  (cost=4.36..291.45 rows=1 width=32) (actual time=0.011..0.011 rows=0 loops=1)
      Filter: ((st_m(timegeom) > '1356998400'::double precision) AND (st_m(timegeom) < '1514764800'::double precision) AND st_contains(timegeom, '0103000000010000002100000000000000008046400000000000003D407CA67EB86767464008BF479B910C3B4013E65FD8901E46408AB5F495542C394042496AF647A84540437FF97DBD71374059E103C018094540523DF87FCEED354060400341214744407E6D2B1370AF34403DA505B5D5694340DC33404FDEC233407E205C32B77942400AB3028F303133400200000000804140000000000000334086DFA3CD4886404008B3028F303133408EB5F495542C3F40D833404FDEC23340467FF97DBD713D407A6D2B1370AF3440543DF87FCEED3B404C3DF87FCEED3540816D2B1370AF3A403C7FF97DBD713740DD33404FDEC2394081B5F495542C39400AB3028F30313940FFBE479B910C3B400000000000003940F7FFFFFFFFFF3C4007B3028F30313940EF40B8646EF33E40D633404FDEC2394037A505B5D5694040776D2B1370AF3A405B40034121474140483DF87FCEED3B4054E103C018094240377FF97DBD713D403E496AF647A842407EB5F495542C3F4011E65FD8901E43407DDFA3CD488640407AA67EB867674340F9FFFFFFFF7F4140000000000080434075205C32B77942407DA67EB86767434035A505B5D569434016E65FD8901E4340584003412147444046496AF647A8424052E103C0180945405EE103C0180942403C496AF647A84540674003412147414010E65FD8901E464044A505B5D56940407AA67EB8676746400B41B8646EF33E4000000000008046400000000000003D40'::geometry))
      ->  Bitmap Index Scan on idx_t_geom  (cost=0.00..4.36 rows=10 width=0) (actual time=0.009..0.009 rows=0 loops=1)
            Index Cond: (timegeom ~~ '0103000000010000002100000000000000008046400000000000003D407CA67EB86767464008BF479B910C3B4013E65FD8901E46408AB5F495542C394042496AF647A84540437FF97DBD71374059E103C018094540523DF87FCEED354060400341214744407E6D2B1370AF34403DA505B5D5694340DC33404FDEC233407E205C32B77942400AB3028F303133400200000000804140000000000000334086DFA3CD4886404008B3028F303133408EB5F495542C3F40D833404FDEC23340467FF97DBD713D407A6D2B1370AF3440543DF87FCEED3B404C3DF87FCEED3540816D2B1370AF3A403C7FF97DBD713740DD33404FDEC2394081B5F495542C39400AB3028F30313940FFBE479B910C3B400000000000003940F7FFFFFFFFFF3C4007B3028F30313940EF40B8646EF33E40D633404FDEC2394037A505B5D5694040776D2B1370AF3A405B40034121474140483DF87FCEED3B4054E103C018094240377FF97DBD713D403E496AF647A842407EB5F495542C3F4011E65FD8901E43407DDFA3CD488640407AA67EB867674340F9FFFFFFFF7F4140000000000080434075205C32B77942407DA67EB86767434035A505B5D569434016E65FD8901E4340584003412147444046496AF647A8424052E103C0180945405EE103C0180942403C496AF647A84540674003412147414010E65FD8901E464044A505B5D56940407AA67EB8676746400B41B8646EF33E4000000000008046400000000000003D40'::geometry)
    Planning Time: 1.393 ms
    Execution Time: 0.181 ms
    
    新建索引后的相同查询:
    Bitmap Heap Scan on huge_spatial_table  (cost=17.90..46.92 rows=1 width=32) (actual time=0.011..0.012 rows=0 loops=1)
      Recheck Cond: ((st_m(timegeom) > '1356998400'::double precision) AND (st_m(timegeom) < '1514764800'::double precision))
      Filter: st_contains(timegeom, '0103000000010000002100000000000000008046400000000000003D407CA67EB86767464008BF479B910C3B4013E65FD8901E46408AB5F495542C394042496AF647A84540437FF97DBD71374059E103C018094540523DF87FCEED354060400341214744407E6D2B1370AF34403DA505B5D5694340DC33404FDEC233407E205C32B77942400AB3028F303133400200000000804140000000000000334086DFA3CD4886404008B3028F303133408EB5F495542C3F40D833404FDEC23340467FF97DBD713D407A6D2B1370AF3440543DF87FCEED3B404C3DF87FCEED3540816D2B1370AF3A403C7FF97DBD713740DD33404FDEC2394081B5F495542C39400AB3028F30313940FFBE479B910C3B400000000000003940F7FFFFFFFFFF3C4007B3028F30313940EF40B8646EF33E40D633404FDEC2394037A505B5D5694040776D2B1370AF3A405B40034121474140483DF87FCEED3B4054E103C018094240377FF97DBD713D403E496AF647A842407EB5F495542C3F4011E65FD8901E43407DDFA3CD488640407AA67EB867674340F9FFFFFFFF7F4140000000000080434075205C32B77942407DA67EB86767434035A505B5D569434016E65FD8901E4340584003412147444046496AF647A8424052E103C0180945405EE103C0180942403C496AF647A84540674003412147414010E65FD8901E464044A505B5D56940407AA67EB8676746400B41B8646EF33E4000000000008046400000000000003D40'::geometry)
      ->  BitmapAnd  (cost=17.90..17.90 rows=1 width=0) (actual time=0.009..0.010 rows=0 loops=1)
            ->  Bitmap Index Scan on idx_t_geom  (cost=0.00..4.36 rows=10 width=0) (actual time=0.009..0.009 rows=0 loops=1)
                  Index Cond: (timegeom ~~ '0103000000010000002100000000000000008046400000000000003D407CA67EB86767464008BF479B910C3B4013E65FD8901E46408AB5F495542C394042496AF647A84540437FF97DBD71374059E103C018094540523DF87FCEED354060400341214744407E6D2B1370AF34403DA505B5D5694340DC33404FDEC233407E205C32B77942400AB3028F303133400200000000804140000000000000334086DFA3CD4886404008B3028F303133408EB5F495542C3F40D833404FDEC23340467FF97DBD713D407A6D2B1370AF3440543DF87FCEED3B404C3DF87FCEED3540816D2B1370AF3A403C7FF97DBD713740DD33404FDEC2394081B5F495542C39400AB3028F30313940FFBE479B910C3B400000000000003940F7FFFFFFFFFF3C4007B3028F30313940EF40B8646EF33E40D633404FDEC2394037A505B5D5694040776D2B1370AF3A405B40034121474140483DF87FCEED3B4054E103C018094240377FF97DBD713D403E496AF647A842407EB5F495542C3F4011E65FD8901E43407DDFA3CD488640407AA67EB867674340F9FFFFFFFF7F4140000000000080434075205C32B77942407DA67EB86767434035A505B5D569434016E65FD8901E4340584003412147444046496AF647A8424052E103C0180945405EE103C0180942403C496AF647A84540674003412147414010E65FD8901E464044A505B5D56940407AA67EB8676746400B41B8646EF33E4000000000008046400000000000003D40'::geometry)
            ->  Bitmap Index Scan on idx_t_geom_m  (cost=0.00..13.29 rows=500 width=0) (never executed)
                  Index Cond: ((st_m(timegeom) > '1356998400'::double precision) AND (st_m(timegeom) < '1514764800'::double precision))
    Planning Time: 0.621 ms
    Execution Time: 0.044 ms
    

    演示1:db&lt;&gt;fiddle

    演示2:db&lt;&gt;fiddle

    注意:PostgreSQL 9.6 将在 5 个月后 EOL,所以我强烈建议您升级您的系统(目前是 13)。你错过了很多真正重要的功能。

    【讨论】:

    • 感谢您回答和测试解决方案:) 我会测试这个,不过索引这个巨大的表需要一些时间。
    • 我们很快会将 PostgreSQL/PostGIS 升级到 Azure 中的最新版本,遗憾的是只有 PostgreSQL 11 和 PostGIS 2.5.1。
    • @kau 也许这个测试场景能更好地重现你的环境? dbfiddle.uk/… 最终将取决于 m 维度的分布,但在我运行的场景中,我使用新索引至少快了三倍。您是否考虑过解析这些信息并将其存储在单独的列中并将其用作分区?
    • @kau 耻辱。自 PostgreSQL 11 和 PostGIS 2.5 以来发生了很多事情......但它绝对比你当前的环境更好;)干杯
    • 在 st_m(geometry) 上创建索引并清理并没有改变我的情况下的查询计划,其中未使用新的 st_m 索引(过滤如前)。我看到这对您的虚拟数据有影响,所以可能与我的旧 Postgres 版本有关。在这一点上,我不明白在几何中嵌入度量的意义。在这种情况下,使用时间戳列而不是使用嵌入时间的 PointZM 似乎更简单。我希望 gist_geometry_ops_nd 索引可以处理 4-D 数据,但情况可能并非如此......
    猜你喜欢
    • 2013-10-14
    • 1970-01-01
    • 2012-05-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-08-03
    • 1970-01-01
    相关资源
    最近更新 更多