加入两张桌子

时间:2016-04-15 05:21:10

标签: sql postgresql postgis postgresql-9.3

我有以下表格是postgres(postgis)。两个表都有第1,第2,第3列类型字符变化(9000)和第4列类型“几何”(包含(纬度,经度)的POINT几何):

Table1
Column1      Column2             Column3    the_geom
Oklahoma     numericalValue1     719        NULL
Oklahoma     geometry            NULL       (34.6,95.3)
Oklahoma     liesIn              America    NULL

Table2
Column1        Column2            Column3     the_geom
Mississippi    liesIn             America     NULL
Mississippi    geometry           NULL        (32.7,-89.53)
Mississippi    numericalValue2    15.3        NULL

我想在表1和表2上运行以下查询来执行空间连接。问题中显示的表1和表2是玩具表,在我的实际数据集中,它们每个包含一百万行。当我运行下面给出的查询时,我发现我的查询需要特别长的时间(超过10小时)才能运行。有人可以建议我是否有办法通过重新构造查询来优化查询。

select * from Table1 s1, Table1 s2, Table1 s3, Table2 s4, Table2 s5, Table2 s6 where
s1.column2='numericalValue1' and     
s2.column2='geometry' and 
s3.column2='liesIn' and 
s1.column1=s2.column1 and 
s2.column1=s3.column1 and 
s4.column2='liesIn' and 
s5.column2='geometry' and 
s6.column2='numericalValue2' and 
s4.column1=s5.column1 and 
s5.column1=s6.column1 and 
ST_DWithin(s2.the_geom, s5.the_geom, 5) 
order by (cast(s1.column3 as double precision)+cast(s6.column3 as double precision)) 
limit 1;

2 个答案:

答案 0 :(得分:2)

  1. 交换轴顺序,使您的几何形状为(X Y)或(长纬度)
  2. 如果您没有GiST空间索引,请调查如何添加一个
  3. 我假设您使用的是SRID = 4326或EPSG:4326,它具有度数单位。所以5000万的距离是不合逻辑和庞大的,并且需要花费很长时间才能进行交叉连接。尝试较小的距离,例如0.01度,或使用geography类型调查以使用线性距离或其他技巧。

答案 1 :(得分:1)

添加到@MikeT的答案,首先确保两个表都有subject的索引和column2 / predicate的索引。

我会说100万行不是那么多,即使顺序扫描也会在几秒钟内完成。如果一个查询花费的时间超过1-2分钟(更不用说10个小时!),我们有充分的理由相信查询中的某些内容已关闭(就像在这种情况下,正如Mike所述,s2和s5之间的虚拟交叉连接,产生了十亿元组,或查询需要缺少索引。

我发现使用连接非常有用(而不是在where子句中具有所有连接条件),以使调试查询更容易。例如,下面的查询与您的查询完全相同,但您可以轻松地在s1,s3,s4和s6上注释掉连接,以尝试隔离并查明问题。

select *
from Table1 s2
join Table2 s5 on (ST_DWithin(s2.the_geom, s5.the_geom, 50000000))
join Table1 s1 on (s1.subject=s2.subject and s1.column2='numericalValue1')
join Table1 s3 on (s2.subject=s3.subject and s3.column2='liesIn')
join Table2 s4 on (s4.subject=s5.subject and s4.column2='liesIn')
join Table2 s6 on (s5.subject=s6.subject and s6.predicate='numericalValue2')
where s2.column2='geometry' and s5.column2='geometry'
order by (cast(s1.column3 as double precision)+cast(s6.column3 as double precision)) 
limit 1