背景
我有一个Java应用程序,它定期从一个数据库(MySQL)获取结果集,并尝试在另一个数据库中查找匹配项(Postgres / PostGIS具体)。
问题
目前,应用程序在Postgres数据库中查询一次结果集中的MySQL记录(可能超过数万)。我正在尝试更改算法,以便应用程序生成一个查询,如果找到任何匹配项,将产生多个结果。另一种描述我的目标的方法是,如果这两个表存在于同一个数据库系统中,那么查询的行为应该与典型的JOIN类似。
当前解决方案
为了解决这个问题,我在FROM
子句中创建了一个虚拟表。但是,我知道如何从值列表中执行此操作的唯一方法是编写使用SELECT
连接的单个UNION
语句。结果似乎有效,虽然我没有使用数千条记录测试性能,但使用数百个此类SELECT
- UNION
语句似乎没有产生任何重大影响。这是整个查询的相关部分,用于说明到目前为止我所做的工作:
SELECT *, ST_Distance_Sphere(latlng, geom) as distance
FROM rwis_sites
INNER JOIN
(SELECT 1100 as unit_id, ST_GeomFromText('POINT(-81.19701 32.09279)', 4326) as geom UNION
SELECT 1100 as unit_id, ST_GeomFromText('POINT(-81.19682 32.09224)', 4326) as geom
UNION
SELECT 1100 as unit_id, ST_GeomFromText('POINT(-81.1968 32.09213)', 4326) as geom
UNION
... just a few more...hundred...thousand...
SELECT 2266 as unit_id, ST_GeomFromText('POINT(-97.98719 29.57656)', 4326) as geom
UNION
SELECT 2266 as unit_id, ST_GeomFromText('POINT(-97.98815 29.57602)', 4326) as geom
) virtualTable
ON ST_Distance_Sphere(latlng, geom) < 10000
ORDER BY ST_Distance_Sphere(latlng, geom) ASC limit 1
由于“虚拟表”是以编程方式生成的,因此我的工作很少。
问题
然而,我担心这是否是一种“愚蠢”的方法(更不用说我还没有发现任何性能问题),最后我想知道:有没有更好的方法来创造类似的东西而没有成千上万的SELECT
- UNION
声明?
答案 0 :(得分:5)
以下是动态创建values表格的更好方法
select *
from (
values
(1100::int, 'POINT(-81.19701 32.09279)'::geography(Point)),
(1100::int, 'POINT(-81.19682 32.09224)'::geography(Point))
) as t(unit_id, geom)
然而,更好的想法可能是使用foreign data wrapper将您的mysql表带入PG。
修改强>
您可能希望尝试预览主表中的记录,前提是它已被ST_Dwithin(latlng, geom, 0.1)
编入索引,前提是0.1°只是slightly more(精神成本(32.09))而不是10000米。 / p>
答案 1 :(得分:1)
首先,我建议使用&#34; UNION ALL&#34;而不是&#34; UNION&#34;。当您使用UNION时,它会尝试删除重复项,这是您不需要它执行的工作。由于您有数千个值,因此检查重复项将变得很慢。
我想不出另一种方法,而不是SELECT在一个SQL语句中填充虚拟表。您可能尝试在一个SQL语句中填充临时表,然后在一秒内完成连接。但是,这会带来交易问题,因此您可能希望坚持使用它的方式。
作为另一个表现有用的提示,您的内部联接正在评估
ST_Distance_Sphere(latlng, geom) < 10000
对于rwis_sites中的每个记录和虚拟表中的(可能是数千个)记录的每个组合,它无法使用索引来优化它。如果在点的一个轴上建立索引,则在连接中使用10000的范围,并将ST_Distance_Sphere移动到where子句,它可能会更快地运行。矛盾的是,你正在添加更多的工作,但是如果它首先检查了范围,它可以使用索引来取消许多组合的资格,并且只检查点在一个轴上靠近时的实际距离。