我正在处理一个生产级项目,该项目对大型表 [超过 1500 万行] 进行空间查询
我们正在使用
MariaDB 10.10.6
,以及 springboot 2.7.18
我添加了休眠空间的额外依赖项,并且空间查询按预期工作
该项目托管在专用服务器中,机器足够好,可以使用
96 cores and 256GB ram
数据库只有一张包含空间数据(一个点)的表,该表还有大约30个其他列,我已经为指定列创建了空间索引,并且还为大多数其他列创建了索引
但是在多边形内查找行的简单选择需要大约 30 秒才能填充 20 大小的页面
select
*
from
announces a
where
(
ST_Within(a.point, ST_GeomFromText('MULTIPOLYGON(((-46.6043151 -23.5172944, -46.5912849 -23.5172944, -46.5912849 -23.5315056, -46.6043151 -23.5315056, -46.6043151 -23.5172944)))',4326))=1
)
order by
a.id asc limit 1;
最奇怪的是,如果我输入数据库中不存在的坐标(例如南极),则只需 17 秒即可运行
我考虑过将此表移动到内存中,但 maria db 不允许使用内存引擎来处理具有空间的表
我真的没有主意了,任何人都可以为我提供有关如何提高此查询/表性能的建议
====================================
好吧,我缩小了问题范围,由于
=1
后缀,mariadb 确实忽略了空间索引
问题是:这个后缀是hibernate在使用空间查询时自动添加的...JPA查询是:
SELECT a FROM Announce a WHERE within(a.point, :#{#filter.multiPolygon})=true
但是,如果我从此查询中删除= true,休眠会崩溃并且系统将无法启动
我不想使用本机查询,有什么方法可以告诉 hibernate 在不使 =1 的情况下工作吗????
我找到了解决方案,希望答案可以帮助将来的人。
这对于由于休眠使用强制比较而遇到索引问题的任何人来说可能很有用
为了澄清,我花了很长时间假设我使用的空间错误,或者数据库中的点和索引错误,或者 MultiPolygon 是问题......但这都不是查询缓慢的原因
MariaDB 无法在函数结果相等的情况下使用空间索引
同时,hibernate 强制我们对函数返回值进行比较,这会使查询始终生成
=1
,从而破坏索引搜索
我想过使用
native = true
,这可能确实解决了问题,但我基本上发现在 JPA 项目中使用本机查询很丑陋
相反,我扩展了 hibernate 使用的方言来生成一个看起来像我想要的查询
public class MariaDB103SpatialDialectExtended extends MariaDB103SpatialDialect {
public MariaDB103SpatialDialectExtended() {
super();
registerFunction("within", new StandardSQLFunction("ST_Within", StandardBasicTypes.BOOLEAN) {
@Override
public String render(Type firstArgumentType, List arguments, SessionFactoryImplementor sessionFactory) {
return super.render(firstArgumentType, arguments, sessionFactory) + " AND 1";
}
});
}
}
通过这种方式,我覆盖了函数渲染中的默认设置以包含
AND 1
,因此它将被重新化为
ST_Within(a.point, ST_GeomFromText('MULTIPOLYGON(......)',4326)) AND 1=1
MariaDB 足够聪明,可以忽略
1=1
,从而使用空间索引