在FROM子句中创建一个大型虚拟表

时间:2014-06-03 18:28:15

标签: sql postgresql

背景

我有一个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声明?

2 个答案:

答案 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子句,它可能会更快地运行。矛盾的是,你正在添加更多的工作,但是如果它首先检查了范围,它可以使用索引来取消许多组合的资格,并且只检查点在一个轴上靠近时的实际距离。