sql - 进行内部连接时,索引顺序很慢

标签 sql postgresql performance

我正在尝试使用 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"

最佳答案

这个解释似乎很简单。您正在连接两个表,AlertsSubscriptionFeed .并且您想要查看具有最高日期的二十个结果行。每个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/

相关文章:

performance - vuetify 列表性能问题

c - Eventloop 具有高 ksoftirqd 负载; nginx 不会,但会执行相同的系统调用。为什么?

sql - CONTAINS 与条件逻辑组合时的效率问题

sql - Ecto - 表 B 或 C 的表 A 的外键约束,但不是 B 和 C

ruby-on-rails - 如何在 PostgreSQL 数据库中存储类哈希对象?

MySQL - InnoDB,缓存查询的一部分以加快执行时间

SQL - WHERE 中的 CASE 表达式

php - SQL 注入(inject) - 向表中插入数据

postgresql - 从存储过程更新

postgresql - 如何在 Vercel 无服务器函数中处理 Postgres 连接池? (“too many connections for role” )