我正在尝试使用 ORDER BY
子句连接两个简单的表
表格:
警报:
- 总行数:
690000
- 索引:
(createdAt DESC, id DESC)
订阅源:
- 总行数:
99990
- 索引:
(createdAt DESC)
问题是当我添加 ORDER BY a."createdAt"DESC, a.id DESC
时,查询变得比使用 ORDER BY sf."createdAt"DESC
我需要的查询及其解释计划
查询:
SELECT a.id, a."createdAt", sf."name"
FROM "Alerts" as a
INNER JOIN "SubscriptionFeed" as sf
ON a.id = sf."alertId"
ORDER BY a."createdAt" DESC, a.id DESC
LIMIT 20
简单解释:
"Limit (cost=0.84..81.54 rows=20 width=24) (actual time=7.926..5079.614 rows=20 loops=1)"
" -> Nested Loop (cost=0.84..403440.05 rows=99990 width=24) (actual time=7.923..5079.604 rows=20 loops=1)"
" -> Index Only Scan using idx_created_at_uuid on "Alerts" a (cost=0.42..69639.05 rows=690000 width=24) (actual time=5.897..3697.758 rows=630013 loops=1)"
" Heap Fetches: 630013"
" -> Index Only Scan using "SubscriptionFeed_alertId_subscriptionId_key" on "SubscriptionFeed" sf (cost=0.42..0.46 rows=2 width=16) (actual time=0.002..0.002 rows=0 loops=630013)"
" Index Cond: ("alertId" = a.id)"
" Heap Fetches: 20"
"Planning Time: 30.234 ms"
"Execution Time: 5079.773 ms"
带有 ORDER BY sf."createdAt"DESC
的查询及其解释计划
查询:
SELECT a.id, a."createdAt", sf."name"
FROM "Alerts" as a
INNER JOIN "SubscriptionFeed" as sf
ON a.id = sf."alertId"
ORDER BY sf."createdAt" DESC
LIMIT 20
解释计划:
"Limit (cost=0.84..28.91 rows=20 width=32) (actual time=1.785..2.708 rows=20 loops=1)"
" -> Nested Loop (cost=0.84..140328.41 rows=99990 width=32) (actual time=1.784..2.703 rows=20 loops=1)"
" -> Index Only Scan using idx_subscription_feed_alert_id on "SubscriptionFeed" sf (cost=0.42..6582.83 rows=99990 width=24) (actual time=1.705..2.285 rows=20 loops=1)"
" Heap Fetches: 20"
" -> Index Scan using "Alerts_pkey" on "Alerts" a (cost=0.42..1.34 rows=1 width=24) (actual time=0.019..0.019 rows=1 loops=20)"
" Index Cond: (id = sf."alertId")"
"Planning Time: 3.758 ms"
"Execution Time: 2.865 ms"
最佳答案
这个解释似乎很简单。您正在连接两个表,Alerts
和 SubscriptionFeed
.并且您想要查看具有最高日期的二十个结果行。每个SubscriptionFeed
行属于 Alerts
行,但不是每个 Alerts
行必然相关SubscriptionFeed
行。
所以,当你想要最新的SubscriptionFeed
行,这很简单:取最后 20 个 SubscriptionFeed
行(来自索引),加入他们的 20 Alerts
行,你就完成了。
当你想要最新的Alerts
相反,DBMS 将使用最后一个 Alerts
行,加入它的所有订阅,检查它是否已经有二十行,如果没有,则取下一个 Alerts
行,再次加入它的所有订阅,检查是否达到了二十行,等等。好吧,DBMS 可能会使用另一种算法,但它永远不会像最新的 SubscriptionFeed
那样简单。 .
就是这样。我们不太可能得到 Alerts
查询速度几乎与 SubscriptionFeed
一样快询问。但我们可以考虑如何帮助 DBMS 访问行:您现有的索引 Alerts(createdAt DESC, id DESC)
帮助 DBMS 快速找到最新的 Alerts
行。为了得到他们的相关SubscriptionFeed
很快,您需要关于 SubscriptionFeed(alertId)
的索引. (好吧,考虑到 SubscriptionFeed.alertId
引用了 Alerts.id
,也许您已经有了。)
除此之外,您还可以提供覆盖索引,其中包含您在查询中使用的表中的所有列(即将其他列添加到已经提到的索引中),例如:
create index idx on SubscriptionFeed(alertId, name);
关于sql - 进行内部连接时,索引顺序很慢,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55773564/