sql - 按地理距离过滤的简单 SQL 查询非常慢
问题描述
这是我的查询:
SELECT 1
FROM post po
WHERE ST_DWithin(po.geog, (SELECT geog FROM person WHERE person.person_id = $1), 20000 * 1609.34, false)
ORDER BY post_id DESC
LIMIT 5;
这是EXPLAIN ANALYZE
:
我对所有内容都有索引,所以我不确定为什么这很慢。按满足子句排序时的前 5 个帖子post_id DESC
,那么这不应该立即返回吗?
我注意到,如果我将 ST_DWithin 调用替换为 ST_Distance 调用,它会立即运行,如下所示:
SELECT 1
FROM post po
WHERE ST_Distance(po.geog, (SELECT geog FROM person WHERE person.person_id = $1)) < 20000 * 1609.34
ORDER BY post_id DESC
LIMIT 5;
那一个以.15
毫秒为单位运行。所以,简单的解决方案就是用 ST_Distance 调用替换 ST_DWithin 调用,不是吗?
好吧,不幸的是不是,因为它并不总是匹配的前 5 行。有时它必须深入扫描表,所以此时 ST_DWithin 更好,因为它可以使用地理索引,而 ST_Distance 不能。
我认为这可能是 postgres 的查询计划器搞砸的问题?就像,出于某种原因,它认为它需要对整个表进行扫描,尽管该ORDER BY x LIMIT 5
子句位于前面和中心?没有把握..
解决方案
您使用的距离几乎是赤道的长度,因此您可以期望(几乎)所有结果都满足此条款。
由于ST_DWithin
使用了空间索引,规划器(错误地)认为使用它首先过滤掉行会更快。然后它必须订购(几乎)所有行,最后将保留前 5 行。
使用 时st_distance
,不能使用空间索引,规划者将选择不同的计划,可能依赖于 上的索引post_id
,这非常快。但是当要返回的行数 (the limit
) 增加时,将使用不同的计划,并且计划者可能认为计算所有行的距离会再次更快。
推荐阅读
- azure - 拉取后 ACI 缓存 docker 图像
- r - 具有数字模式的字符串中的字符数(在 R 中)?
- c# - PDFsharp (1.50.5147) 设置 OwnerPassword 混淆了文档颜色
- python-sphinx - 构建文档时如何告诉 sphinx 忽略“包含”指令?
- python - 如何自定义 Django 的默认邮件模板?(smtpd)
- c - 如果条件为真,如何返回结构,如果条件为假,如何返回 int
- php - (Wordpress) 我将 WooCommerce 产品的模板更改为类别图像,但图像仍未显示
- hadoop - Hive Joins 可以在 Apache Nifi 中实现吗?
- laravel - 用关系复制一些数据
- c# - 将 observable 集合绑定到 listview 不会传递 Xamarin.iOS 中的项目