我正在尝试在 Java EE 中构建一个基于位置的应用程序,它从给定坐标的某个半径返回提供者作为输入。当我使用 JPA 时,我找不到使用命名查询来查询数据库的解决方案,因为它不支持 Sin、Cos 等函数。我在这里找到了一个不错的读物sql-havesine,我可以在其中使用本机而是查询。查询在数据库 (Postgres) 上执行速度很快(33 毫秒),但从应用程序执行时非常慢(> 800 毫秒)。
有没有办法从应用程序端加快速度,或者您是否必须使用数据库中的存储过程之类的东西。
我的方法如下所示:
@SuppressWarnings("unchecked")
public List<Company> findCompaniesByProximity(Coordinate coordinate, int distance) {
double latitude = coordinate.getLatitude();
double longitude = coordinate.getLongitude();
String sql = "SELECT * FROM ("
+ "SELECT *, c.distance_unit * DEGREES(ACOS(COS(RADIANS(c.lat)) * COS(RADIANS(companies.latitude)) * "
+ "COS(RADIANS(c.lng) - RADIANS(companies.longitude)) + SIN(RADIANS(c.lat)) * SIN(RADIANS(companies.latitude)))"
+ ") AS distance "
+ "FROM Companies "
+ "JOIN (SELECT ?1 AS lat, ?2 AS lng, ?3 AS search_radius, 111.045 AS distance_unit) "
+ "AS c ON 1=1 "
+ "WHERE companies.latitude "
+ "BETWEEN c.lat - (c.search_radius / c.distance_unit) "
+ "AND c.lat + (c.search_radius / c.distance_unit) "
+ "AND companies.longitude "
+ "BETWEEN c.lng - (c.search_radius / (c.distance_unit * COS(RADIANS(c.lat)))) "
+ "AND c.lng + (c.search_radius / (c.distance_unit * COS(RADIANS(c.lat))))"
+ ") AS proximity "
+ "WHERE distance <= search_radius "
+ "ORDER BY distance "
+ "LIMIT 25";
List<Company> companies = null;
try {
Query query = em.createNativeQuery(sql, Company.class);
query.setParameter(1, latitude);
query.setParameter(2, longitude);
query.setParameter(3, distance / 1000.0);
companies = (List<Company>) query.getResultList();
} catch (IllegalArgumentException e) {
System.err.println("Argument is invalid " + e);
} catch (PersistenceException e) {
System.err.println("PersistenceException: " + e.getMessage());
}
return companies;
}
该方法是从单例 EJB 调用的,我将 Payara 服务器与 Postgres 和 EclipseLink 一起使用。一切都在本地调用,所以我认为与数据库的连接会快得多。我也尝试了 postgres earthdistance 扩展,但它更慢(> 1800 毫秒)。我对编程非常陌生,尤其是 Java EE,所以我可能在此过程中做错了什么:) 提前谢谢。