为了提高时空查询的性能,需要确保查询条件能够使用到时空索引,从而避免全表扫描。本文介绍时空查询的优化方法。
时空查询的优化
当查询条件只有空间范围或者包含空间范围和时间范围时,创建时空索引需要使用
Z-ORDER
索引函数对空间列或者时间列进行时空编码,即Z-ORDER(geometry)
或者Z-ORDER(geometry,time)
类型。在查询语句中请注意以下几点:Z-ORDER
索引函数的入参会影响时空查询的性能,查询条件中必须包含Z-ORDER
索引函数的所有列,才能使用时空索引。- 如果
Z-ORDER
索引函数对空间范围和时间范围组合进行时空编码,那么查询条件中必须同时包含时间的上限和下限,才能使用时空索引。
下表列举了不同的
Z-ORDER
索引函数类型对查询操作的影响,其中g为空间类型的列,t为时间类型的列。查询条件 | 查询语句 | Z-ORDER(g) | Z-ORDER(g,t) |
---|---|---|---|
只有空间范围 | SELECT id FROM point_table WHERE ST_Contains(ST_GeomFromText('POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))'),g); | 可以使用Z-ORDER 索引函数加速查询。 | 不能使用Z-ORDER 索引函数加速查询,因为Z-ORDER 索引函数是对g和t建立的索引,查询条件必须同时包含空间范围和时间范围才能使用时空索引。 |
包含空间范围和时间范围 | SELECT id FROM point_table WHERE ST_Contains(ST_GeomFromText('POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))'),g) AND t>'2021-01-01 08:21:00' AND t<'2021-01-01 08:23:00'; | 可以使用Z-ORDER 索引函数加速查询。 | 可以使用Z-ORDER 索引函数加速查询。 |
SELECT id FROM point_table WHERE ST_Contains(ST_GeomFromText('POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))'),g) AND t > '2021-01-01 08:21:00'; | 可以使用Z-ORDER 索引函数加速查询。 | 不能使用Z-ORDER 索引函数加速查询,因为时间条件不是闭合范围。 |
组合查询的优化
如果查询条件中包含时空范围和其他列,为了加快时空查询的速度,建议构建组合索引。组合索引是指主键索引或者二级索引中包含Z-ORDER
索引函数和其他列,例如PRIMARY KEY(Z-ORDER(g,t), id)
。由于Z-ORDER
索引函数返回的是一个编码值,可以将Z-ORDER
当作一列。关于Lindorm宽表的组合索引介绍,请参见查询优化。
并行查询的优化
在开启并行查询的条件下,可以使用Sharding来提高并行查询的并行度,从而提高查询性能。
Sharding是指将数据进行分片的方法。创建时空索引时使用Sharding可以使数据更加分散。同时,使用Sharding可以在写入数据时将空间或时空相邻的数据写入到索引表的不同位置,进而写入到数据库物理存储的不同分片中。
您可以通过Z-ORDER
索引函数,为数据类型为点(Point)的列创建时空索引,并指定索引分片(Shard)的数量numShards,即Z-ORDER(Point, numShards)
。指定numShards后,索引值相邻的numShards条数据前会被依次加上0 - numShards-1
前缀,并被写入到索引表的不同位置。
以下示例对比了使用Sharding前后的查询效率:
使用Sharding前:- 对于数据类型为Point,数据量约为1.5亿的示例表,创建不设置numShards参数的空间索引表table_noshard。
CREATE TABLE table_noshard(id INT, g GEOMETRY(POINT), name VARCHAR, PRIMARY KEY(Z-ORDER(g)));
- 对空间索引表table_noshard开启并行查询。
SELECT /*+_l_enable_parallel_(8)*/ id FROM table_noshard WHERE ST_Contains(ST_GeomFromText('POLYGON((...))'), g);
返回结果为2058894,耗时10986ms。
- 创建对照组。对同一示例表,建立numShards值为8的空间索引表table_shard8。
CREATE TABLE table_shard8(id INT, g GEOMETRY(POINT), name VARCHAR, PRIMARY KEY(Z-ORDER(g, 8)));
- 对空间索引表table_shard8开启并行查询。
SELECT /*+_l_enable_parallel_(8)*/ id FROM table_shard8 WHERE ST_Contains(ST_GeomFromText('POLYGON((...))'), g);
返回结果为2058894,耗时2501ms。
可以看到,两种方式的返回结果完全相同,但设置了numShards参数后并行查询的耗时明显缩短,查询效率大幅提升。
不规则范围查询的优化
创建时空索引后,当查询范围的形状与其矩形外包框(索引过滤范围)相差较大时,索引过滤的效果并不理想,如下图所示。
当数据量较大时,可以通过设置HINT的/*+_l_enable_enhanced_filter_*/ 参数来开启索引过滤增强功能。
例如,为表gtest(g列已创建时空索引,POLYGON((...))为不规则范围)开启索引过滤增强功能:
SELECT /*+_l_enable_enhanced_filter_*/ id FROM gtest WHERE ST_Contains(ST_GeomFromText('POLYGON((...))'), g);
说明 索引过滤增强功能默认不开启,在数据量较小的情况下无需使用。