2013-11-01 36 views
0

我需要建议,因为我不够好。PostgreSQL如何创建可扩展的基于位置的查询

我在AWS(亚马逊网络服务)上运行的PostgreSQL中有一个数据库。 我有一个表“user_location”,其中存储每个用户的位置,现在有超过300万行。

我有经常运行下面的查询,以便脚本来看看两个用户都在附近:

SELECT 
    UL.id       AS id, 
    UL.user_id      AS user_id, 
    ST_X(UL.location::geometry) AS lat, 
    ST_Y(UL.location::geometry) AS lng, 
    UL.datetime     AS datetime 
FROM 
    public.user_location AS UL 
WHERE 
    UL.user_id <> 1234567890 AND 
    '1890-10-31 03:00:00 +00:00' - UL.datetime <= interval '1' minute AND 
    '1890-10-31 03:00:00 +00:00' >= UL.datetime AND 
    ST_DWithin(UL.location, ST_GeogFromText('POINT(54 -1)'), 5000) 
ORDER BY 
    UL.datetime DESC; 

这个问题似乎是半径,查询的执行时间通过增加呈指数级增长因为它需要检查更多行。

我需要一个可扩展的解决方案,通过增加给定位置周围的半径,执行时间几乎相同。我需要在日期时间之前和查询中的半径之后使用“水平切割”数据,我该怎么办?

我也EXPLAIN分析哪些是输出:

"Sort (cost=389.72..389.73 rows=3 width=52) (actual time=136848.985..136848.985 rows=0 loops=1)" 
" Sort Key: datetime" 
" Sort Method: quicksort Memory: 25kB" 
" -> Bitmap Heap Scan on user_location ul (cost=11.00..389.70 rows=3 width=52) (actual time=136848.976..136848.976 rows=0 loops=1)" 
"  Recheck Cond: (location && '0101000020E6100000C182458F29494B4095E0C3DB39E3F3BF'::geography)" 
"  Filter: ((user_id <> 1234567890) AND ('1890-10-31 03:00:00 +00:00'::timestamp with time zone >= datetime) AND (('1890-10-31 03:00:00 +00:00'::timestamp with time zone - datetime) <= '00:01:00'::interval minute) AND ('0101000020E6100000C182458F29494B4095E0C3DB39E3F3BF'::geography && _st_expand(location, 5000::double precision)) AND _st_dwithin(location, '0101000020E6100000C182458F29494B4095E0C3DB39E3F3BF'::geography, 5000::double precision, true))" 
"  -> Bitmap Index Scan on users_locations_gix (cost=0.00..11.00 rows=91 width=0) (actual time=4463.249..4463.249 rows=165622 loops=1)" 
"    Index Cond: (location && '0101000020E6100000C182458F29494B4095E0C3DB39E3F3BF'::geography)" 
"Total runtime: 136849.591 ms" 

提前感谢! 干杯

回答

1

在300万行中,您希望减少查询实际需要评估的数量。要做到这一点,如果我们知道你的数据是什么样子,那将是最好的,但是有一些相当简单的事情要考虑。

您指定的分钟内您有多少条目?我想这应该是低的。如果是这样,你可以在UL.datetime上设置一个索引(默认btree一个很好)(不要忘了VACUUM and ANALYZE之后)。然后改变你的查询,以便它能很好地使用它。

UL.datetime BETWEEN '1890-10-31 03:00:00 +00:00' 
       AND '1890-10-31 03:00:00 +00:00' + interval '1' minute AND 

,如果你有这些日期之间有太多的行,我们需要找到一种方法来限制需要通过位置进行评估的。

+0

谢谢@cmd!我认为,通过“...和...之间”,查询变得可靠。我创建了一个索引'(datetime DESC)',但这需要时间。我不知道有多少个条目取决于用户的数量,所以它应该多于或少于1000个条目。 – angelst00ne