Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Slow query upon listing playlists #6386

Open
kontrollanten opened this issue May 8, 2024 · 2 comments
Open

Slow query upon listing playlists #6386

kontrollanten opened this issue May 8, 2024 · 2 comments

Comments

@kontrollanten
Copy link
Contributor

kontrollanten commented May 8, 2024

Describe the current behavior

In our postgres logs we see a lot of the following slow queries:

SELECT
       "VideoPlaylistModel".*,
       "OwnerAccount->Actor->Server"."id" AS "OwnerAccount.Actor.Server.id",
       "OwnerAccount->Actor->Server"."host" AS "OwnerAccount.Actor.Server.host",
       "OwnerAccount->Actor->Avatars"."id" AS "OwnerAccount.Actor.Avatars.id",
       "OwnerAccount->Actor->Avatars"."filename" AS "OwnerAccount.Actor.Avatars.filename",
       "OwnerAccount->Actor->Avatars"."height" AS "OwnerAccount.Actor.Avatars.height",
       "OwnerAccount->Actor->Avatars"."width" AS "OwnerAccount.Actor.Avatars.width",
       "OwnerAccount->Actor->Avatars"."fileUrl" AS "OwnerAccount.Actor.Avatars.fileUrl",
       "OwnerAccount->Actor->Avatars"."onDisk" AS "OwnerAccount.Actor.Avatars.onDisk",
       "OwnerAccount->Actor->Avatars"."type" AS "OwnerAccount.Actor.Avatars.type",
       "OwnerAccount->Actor->Avatars"."actorId" AS "OwnerAccount.Actor.Avatars.actorId",
       "OwnerAccount->Actor->Avatars"."createdAt" AS "OwnerAccount.Actor.Avatars.createdAt",
       "OwnerAccount->Actor->Avatars"."updatedAt" AS "OwnerAccount.Actor.Avatars.updatedAt",
       "VideoChannel->Actor->Server"."id" AS "VideoChannel.Actor.Server.id",
       "VideoChannel->Actor->Server"."host" AS "VideoChannel.Actor.Server.host",
       "VideoChannel->Actor->Avatars"."id" AS "VideoChannel.Actor.Avatars.id",
       "VideoChannel->Actor->Avatars"."filename" AS "VideoChannel.Actor.Avatars.filename",
       "VideoChannel->Actor->Avatars"."height" AS "VideoChannel.Actor.Avatars.height",
       "VideoChannel->Actor->Avatars"."width" AS "VideoChannel.Actor.Avatars.width",
       "VideoChannel->Actor->Avatars"."fileUrl" AS "VideoChannel.Actor.Avatars.fileUrl",
       "VideoChannel->Actor->Avatars"."onDisk" AS "VideoChannel.Actor.Avatars.onDisk",
       "VideoChannel->Actor->Avatars"."type" AS "VideoChannel.Actor.Avatars.type",
       "VideoChannel->Actor->Avatars"."actorId" AS "VideoChannel.Actor.Avatars.actorId",
       "VideoChannel->Actor->Avatars"."createdAt" AS "VideoChannel.Actor.Avatars.createdAt",
       "VideoChannel->Actor->Avatars"."updatedAt" AS "VideoChannel.Actor.Avatars.updatedAt",
       "Thumbnail"."id" AS "Thumbnail.id",
       "Thumbnail"."filename" AS "Thumbnail.filename",
       "Thumbnail"."height" AS "Thumbnail.height",
       "Thumbnail"."width" AS "Thumbnail.width",
       "Thumbnail"."type" AS "Thumbnail.type",
       "Thumbnail"."fileUrl" AS "Thumbnail.fileUrl",
       "Thumbnail"."automaticallyGenerated" AS "Thumbnail.automaticallyGenerated",
       "Thumbnail"."onDisk" AS "Thumbnail.onDisk",
       "Thumbnail"."videoId" AS "Thumbnail.videoId",
       "Thumbnail"."videoPlaylistId" AS "Thumbnail.videoPlaylistId",
       "Thumbnail"."createdAt" AS "Thumbnail.createdAt",
       "Thumbnail"."updatedAt" AS "Thumbnail.updatedAt"
FROM (
       SELECT
              "VideoPlaylistModel"."id",
              "VideoPlaylistModel"."name",
              "VideoPlaylistModel"."description",
              "VideoPlaylistModel"."privacy",
              "VideoPlaylistModel"."url",
              "VideoPlaylistModel"."uuid",
              "VideoPlaylistModel"."type",
              "VideoPlaylistModel"."ownerAccountId",
              "VideoPlaylistModel"."videoChannelId",
              "VideoPlaylistModel"."createdAt",
              "VideoPlaylistModel"."updatedAt",
              0 AS similarity,
(
                     SELECT
                            Count("id")
                     FROM
                            "videoPlaylistElement"
                     WHERE
                            "videoPlaylistId" = "VideoPlaylistModel"."id") AS "videosLength",
                     "OwnerAccount"."id" AS "OwnerAccount.id",
                     "OwnerAccount"."name" AS "OwnerAccount.name",
                     "OwnerAccount"."actorId" AS "OwnerAccount.actorId",
                     "OwnerAccount->Actor"."id" AS "OwnerAccount.Actor.id",
                     "OwnerAccount->Actor"."preferredUsername" AS "OwnerAccount.Actor.preferredUsername",
                     "OwnerAccount->Actor"."url" AS "OwnerAccount.Actor.url",
                     "OwnerAccount->Actor"."serverId" AS "OwnerAccount.Actor.serverId",
                     "VideoChannel"."id" AS "VideoChannel.id",
                     "VideoChannel"."name" AS "VideoChannel.name",
                     "VideoChannel"."description" AS "VideoChannel.description",
                     "VideoChannel"."actorId" AS "VideoChannel.actorId",
                     "VideoChannel->Actor"."id" AS "VideoChannel.Actor.id",
                     "VideoChannel->Actor"."preferredUsername" AS "VideoChannel.Actor.preferredUsername",
                     "VideoChannel->Actor"."url" AS "VideoChannel.Actor.url",
                     "VideoChannel->Actor"."serverId" AS "VideoChannel.Actor.serverId"
              FROM
                     "videoPlaylist" AS "VideoPlaylistModel"
                     INNER JOIN "account" AS "OwnerAccount" ON "VideoPlaylistModel"."ownerAccountId" = "OwnerAccount"."id"
                     INNER JOIN "actor" AS "OwnerAccount->Actor" ON "OwnerAccount"."actorId" = "OwnerAccount->Actor"."id"
                            AND ("OwnerAccount->Actor"."serverId" IS NULL
                                   OR "OwnerAccount->Actor"."serverId" IN (
                                          SELECT
                                                 "actor"."serverId"
                                          FROM
                                                 "actorFollow"
                                          INNER JOIN "actor" ON actor.id = "actorFollow"."targetActorId"
                                   WHERE
                                          "actorFollow"."actorId" = 1))
                            LEFT OUTER JOIN ("videoChannel" AS "VideoChannel"
                            INNER JOIN "actor" AS "VideoChannel->Actor" ON "VideoChannel"."actorId" = "VideoChannel->Actor"."id") ON "VideoPlaylistModel"."videoChannelId" = "VideoChannel"."id"
              WHERE ("VideoPlaylistModel"."privacy" = 1
                     AND "VideoPlaylistModel"."type" = 1
                     AND (
                            SELECT
                                   Count("id")
                            FROM
                                   "videoPlaylistElement"
                            WHERE
                                   "videoPlaylistId" = "VideoPlaylistModel"."id") != 0)
              ORDER BY
                     "similarity" DESC,
                     "VideoPlaylistModel"."id" ASC
              LIMIT 2 offset 58) AS "VideoPlaylistModel"
       LEFT OUTER JOIN "server" AS "OwnerAccount->Actor->Server" ON "OwnerAccount.Actor.serverId" = "OwnerAccount->Actor->Server"."id"
       LEFT OUTER JOIN "actorImage" AS "OwnerAccount->Actor->Avatars" ON "OwnerAccount.Actor.id" = "OwnerAccount->Actor->Avatars"."actorId"
              AND "OwnerAccount->Actor->Avatars"."type" = 1
       LEFT OUTER JOIN "server" AS "VideoChannel->Actor->Server" ON "VideoChannel.Actor.serverId" = "VideoChannel->Actor->Server"."id"
       LEFT OUTER JOIN "actorImage" AS "VideoChannel->Actor->Avatars" ON "VideoChannel.Actor.id" = "VideoChannel->Actor->Avatars"."actorId"
              AND "VideoChannel->Actor->Avatars"."type" = 1
       LEFT OUTER JOIN "thumbnail" AS "Thumbnail" ON "VideoPlaylistModel"."id" = "Thumbnail"."videoPlaylistId"
ORDER BY
       "similarity" DESC,
       "VideoPlaylistModel"."id" ASC;

They usually takes ~1 second to run.

Steps to reproduce

No response

Describe the expected behavior

No response

Additional information

  • PeerTube instance:

    • URL:
    • Version: 6.1.0
    • NodeJS version:
    • Ffmpeg version:
  • Browser name, version and platforms on which you could reproduce the bug:

  • Link to browser console log if relevant:

  • Link to server log if relevant (journalctl or /var/www/peertube/storage/logs/):

@Chocobozzz
Copy link
Owner

Chocobozzz commented May 13, 2024

Hi,

Can you provide the output of your sql query with EXPLAIN ANALYZE?
Can you also provide logs to see what API request is responsible for this SQL call?
Can you also test if the query is slow if you change ORDER BY "similarity" DESC, "VideoPlaylistModel"."id" ASC; to "VideoPlaylistModel"."createdAt" DESC, "VideoPlaylistModel"."id" ASC (in the inner + outer queries)

@Chocobozzz Chocobozzz added the Status: Waiting for answer Waiting issue author answer label May 13, 2024
@kontrollanten
Copy link
Contributor Author

There's a lot of content in our access logs so hard to pin point which API call is responsible. But I'm pretty sure it's one of the GET /api/v1/search calls. When I scrolled through the pagination on our search page it went slow and new slow logs appeared.

Original query
                                                                                                                              QUERY PLAN

--------------------------------------------------------------------------------------------------------------------------------------------------------------
---------------------------------------------------------------------------------------------------------
 Sort  (cost=528736.38..528736.39 rows=1 width=2138) (actual time=1070.385..1070.395 rows=0 loops=1)
   Sort Key: (0) DESC, "VideoPlaylistModel".id
   Sort Method: quicksort  Memory: 25kB
   ->  Nested Loop Left Join  (cost=396536.12..528736.37 rows=1 width=2138) (actual time=1070.330..1070.339 rows=0 loops=1)
         ->  Nested Loop Left Join  (cost=396535.83..528728.07 rows=1 width=1940) (actual time=1070.329..1070.337 rows=0 loops=1)
               ->  Nested Loop Left Join  (cost=396535.55..528719.76 rows=1 width=1765) (actual time=1070.328..1070.336 rows=0 loops=1)
                     Join Filter: ("VideoChannel->Actor"."serverId" = "VideoChannel->Actor->Server".id)
                     ->  Nested Loop Left Join  (cost=396535.55..528717.92 rows=1 width=1245) (actual time=1070.328..1070.335 rows=0 loops=1)
                           ->  Nested Loop Left Join  (cost=396535.27..528709.61 rows=1 width=1070) (actual time=1070.327..1070.334 rows=0 loops=1)
                                 Join Filter: ("OwnerAccount->Actor"."serverId" = "OwnerAccount->Actor->Server".id)
                                 ->  Limit  (cost=396535.27..528707.77 rows=1 width=550) (actual time=1070.326..1070.332 rows=0 loops=1)
                                       ->  Nested Loop Left Join  (cost=17.77..396535.27 rows=3 width=550) (actual time=0.483..43.699 rows=50 loops=1)
                                             ->  Nested Loop  (cost=17.19..396415.30 rows=3 width=290) (actual time=0.411..41.608 rows=50 loops=1)
                                                   ->  Nested Loop  (cost=0.29..396339.15 rows=4 width=228) (actual time=0.368..40.763 rows=54 loops=1)
                                                         Join Filter: ("VideoPlaylistModel"."ownerAccountId" = "OwnerAccount".id)
                                                         Rows Removed by Join Filter: 248386
                                                         ->  Index Scan using "videoPlaylist_pkey" on "videoPlaylist" "VideoPlaylistModel"  (cost=0.29..394642
.64 rows=4 width=210) (actual time=0.271..7.946 rows=54 loops=1)
                                                               Filter: ((privacy = 1) AND (type = 1) AND ((SubPlan 3) <> 0))
                                                               Rows Removed by Filter: 13602
                                                               SubPlan 3
                                                                 ->  Aggregate  (cost=28.79..28.80 rows=1 width=8) (actual time=0.045..0.045 rows=1 loops=71)
                                                                       ->  Index Scan using video_playlist_element_video_playlist_id on "videoPlaylistElement"
 "videoPlaylistElement_1"  (cost=0.29..28.77 rows=7 width=4) (actual time=0.007..0.039 rows=54 loops=71)
                                                                             Index Cond: ("videoPlaylistId" = "VideoPlaylistModel".id)
                                                         ->  Materialize  (cost=0.00..542.14 rows=20076 width=18) (actual time=0.000..0.374 rows=4601 loops=54
)
                                                               ->  Seq Scan on account "OwnerAccount"  (cost=0.00..441.76 rows=20076 width=18) (actual time=0.
016..2.127 rows=13465 loops=1)
                                                   ->  Index Scan using actor_pkey on actor "OwnerAccount->Actor"  (cost=16.90..19.04 rows=1 width=62) (actual
 time=0.014..0.015 rows=1 loops=54)
                                                         Index Cond: (id = "OwnerAccount"."actorId")
                                                         Filter: (("serverId" IS NULL) OR (hashed SubPlan 2))
                                                         Rows Removed by Filter: 0
                                                         SubPlan 2
                                                           ->  Nested Loop  (cost=0.57..16.61 rows=1 width=4) (actual time=0.019..0.021 rows=0 loops=1)
                                                           ->  Index Only Scan using actor_follow_actor_id_target_actor_id on "actorFollow"  (cost=0.28..8.30 rows=1 width=4) (actual time=0.018..0.019 rows=0 loops=1)
                                                           Index Cond: ("actorId" = 1)
                                                           Heap Fetches: 0
                                                     ->  Index Scan using actor_pkey on actor  (cost=0.29..8.31 rows=1 width=8) (never executed)
                                                           Index Cond: (id = "actorFollow"."targetActorId")
                                 ->  Nested Loop  (cost=0.58..11.18 rows=1 width=248) (actual time=0.009..0.009 rows=1 loops=50)
                                       ->  Index Scan using "videoChannel_pkey" on "videoChannel" "VideoChannel"  (cost=0.29..8.30 rows=1 width=186) (actual time=0.005..0.005 rows=1 loops=50)
                                             Index Cond: (id = "VideoPlaylistModel"."videoChannelId")
                                       ->  Index Scan using actor_pkey on actor "VideoChannel->Actor"  (cost=0.29..2.88 rows=1 width=62) (actual time=0.003..0.003 rows=1 loops=50)
                                             Index Cond: (id = "VideoChannel"."actorId")
                                 SubPlan 1
                                   ->  Aggregate  (cost=28.79..28.80 rows=1 width=8) (actual time=0.031..0.031 rows=1 loops=50)
                                         ->  Index Scan using video_playlist_element_video_playlist_id on "videoPlaylistElement"  (cost=0.29..28.77 rows=7 width=4) (actual time=0.003..0.025 rows=76 loops=50)
                                               Index Cond: ("videoPlaylistId" = "VideoPlaylistModel".id)
                     ->  Seq Scan on server "OwnerAccount->Actor->Server"  (cost=0.00..1.37 rows=37 width=520) (never executed)
               ->  Index Scan using actor_image_actor_id_type_width on "actorImage" "OwnerAccount->Actor->Avatars"  (cost=0.28..8.30 rows=1 width=175) (never executed)
                     Index Cond: (("actorId" = "OwnerAccount->Actor".id) AND (type = 1))
         ->  Seq Scan on server "VideoChannel->Actor->Server"  (cost=0.00..1.37 rows=37 width=520) (never executed)
   ->  Index Scan using actor_image_actor_id_type_width on "actorImage" "VideoChannel->Actor->Avatars"  (cost=0.28..8.30 rows=1 width=175) (never executed)
         Index Cond: (("actorId" = "VideoChannel->Actor".id) AND (type = 1))
->  Index Scan using thumbnail_video_playlist_id on thumbnail "Thumbnail"  (cost=0.28..8.30 rows=1 width=198) (never executed)
   Index Cond: ("videoPlaylistId" = "VideoPlaylistModel".id)
Planning Time: 5.314 ms
JIT:
Functions: 87
Options: Inlining true, Optimization true, Expressions true, Deforming true
Timing: Generation 9.825 ms, Inlining 71.154 ms, Optimization 588.283 ms, Emission 365.690 ms, Total 1034.952 ms
Execution Time: 1102.341 ms
(59 rows)
With `"VideoPlaylistModel"."createdAt" DESC, "VideoPlaylistModel"."id" ASC`
                                                                                                                                    QUERY PLAN                
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
 Nested Loop Left Join  (cost=396027.27..396083.83 rows=1 width=2138) (actual time=256.100..256.114 rows=0 loops=1)
   ->  Nested Loop Left Join  (cost=396026.99..396075.53 rows=1 width=1940) (actual time=256.099..256.112 rows=0 loops=1)
         ->  Nested Loop Left Join  (cost=396026.71..396067.22 rows=1 width=1765) (actual time=256.098..256.110 rows=0 loops=1)
               Join Filter: ("VideoChannel->Actor"."serverId" = "VideoChannel->Actor->Server".id)
               ->  Nested Loop Left Join  (cost=396026.71..396065.39 rows=1 width=1245) (actual time=256.097..256.109 rows=0 loops=1)
                     ->  Nested Loop Left Join  (cost=396026.42..396057.07 rows=1 width=1070) (actual time=256.096..256.108 rows=0 loops=1)
                           Join Filter: ("OwnerAccount->Actor"."serverId" = "OwnerAccount->Actor->Server".id)
                           ->  Limit  (cost=396026.42..396055.23 rows=1 width=550) (actual time=256.095..256.106 rows=0 loops=1)
                                 ->  Result  (cost=395940.00..396026.42 rows=3 width=550) (actual time=182.597..184.948 rows=50 loops=1)
                                       ->  Sort  (cost=395940.00..395940.00 rows=3 width=542) (actual time=179.606..179.628 rows=50 loops=1)
                                             Sort Key: "VideoPlaylistModel"."createdAt" DESC, "VideoPlaylistModel".id
                                             Sort Method: quicksort  Memory: 53kB
                                             ->  Nested Loop Left Join  (cost=17.48..395939.97 rows=3 width=542) (actual time=6.570..179.469 rows=50 loops=1)
                                                   ->  Nested Loop  (cost=16.90..395906.39 rows=3 width=290) (actual time=6.524..179.076 rows=50 loops=1)
                                                         ->  Nested Loop  (cost=0.00..395830.24 rows=4 width=228) (actual time=6.461..178.077 rows=54 loops=1)
                                                               Join Filter: ("VideoPlaylistModel"."ownerAccountId" = "OwnerAccount".id)
                                                               Rows Removed by Join Filter: 1076868
                                                               ->  Seq Scan on account "OwnerAccount"  (cost=0.00..441.76 rows=20076 width=18) (actual time=0.015..2.175 rows=19943 loops=1)
                                                               ->  Materialize  (cost=0.00..394183.93 rows=4 width=210) (actual time=0.000..0.003 rows=54 loops=19943)
                                                                     ->  Seq Scan on "videoPlaylist" "VideoPlaylistModel"  (cost=0.00..394183.91 rows=4 width=210) (actual time=0.075..5.170 rows=54 loops=1)
                                                                           Filter: ((privacy = 1) AND (type = 1) AND ((SubPlan 3) <> 0))
                                                                           Rows Removed by Filter: 13602
                                                                           SubPlan 3
                                                                             ->  Aggregate  (cost=28.79..28.80 rows=1 width=8) (actual time=0.040..0.040 rows=1 loops=71)
                                                                                   ->  Index Scan using video_playlist_element_video_playlist_id on "videoPlaylistElement" "videoPlaylistElement_1"  (cost=0.29..28.77 rows=7 width=4) (actual time=0.005..0.035 rows=54 loops=71)
                                                                                         Index Cond: ("videoPlaylistId" = "VideoPlaylistModel".id)
                                                         ->  Index Scan using actor_pkey on actor "OwnerAccount->Actor"  (cost=16.90..19.04 rows=1 width=62) (actual time=0.017..0.017 rows=1 loops=54)
                                                               Index Cond: (id = "OwnerAccount"."actorId")
                                                               Filter: (("serverId" IS NULL) OR (hashed SubPlan 2))
                                                               Rows Removed by Filter: 0
                                                               SubPlan 2
                                                                 ->  Nested Loop  (cost=0.57..16.61 rows=1 width=4) (actual time=0.016..0.018 rows=0 loops=1)
                                                                       ->  Index Only Scan using actor_follow_actor_id_target_actor_id on "actorFollow"  (cost=0.28..8.30 rows=1 width=4) (actual time=0.016..0.016 rows=0 loops=1)
                                                                             Index Cond: ("actorId" = 1)
                                                                             Heap Fetches: 0
                                                                       ->  Index Scan using actor_pkey on actor  (cost=0.29..8.31 rows=1 width=8) (never executed)
                                                                             Index Cond: (id = "actorFollow"."targetActorId")
                                                   ->  Nested Loop  (cost=0.58..11.18 rows=1 width=248) (actual time=0.007..0.007 rows=1 loops=50)
                                                         ->  Index Scan using "videoChannel_pkey" on "videoChannel" "VideoChannel"  (cost=0.29..8.30 rows=1 width=186) (actual time=0.004..0.004 rows=1 loops=50)
                                                               Index Cond: (id = "VideoPlaylistModel"."videoChannelId")
                                                         ->  Index Scan using actor_pkey on actor "VideoChannel->Actor"  (cost=0.29..2.88 rows=1 width=62) (actual time=0.002..0.002 rows=1 loops=50)
                                                               Index Cond: (id = "VideoChannel"."actorId")
                                       SubPlan 1
                                         ->  Aggregate  (cost=28.79..28.80 rows=1 width=8) (actual time=0.047..0.047 rows=1 loops=50)
                                               ->  Index Scan using video_playlist_element_video_playlist_id on "videoPlaylistElement"  (cost=0.29..28.77 rows=7 width=4) (actual time=0.004..0.039 rows=76 loops=50)
                                                     Index Cond: ("videoPlaylistId" = "VideoPlaylistModel".id)
                           ->  Seq Scan on server "OwnerAccount->Actor->Server"  (cost=0.00..1.37 rows=37 width=520) (never executed)
                     ->  Index Scan using actor_image_actor_id_type_width on "actorImage" "OwnerAccount->Actor->Avatars"  (cost=0.28..8.30 rows=1 width=175) (never executed)
                           Index Cond: (("actorId" = "OwnerAccount->Actor".id) AND (type = 1))
               ->  Seq Scan on server "VideoChannel->Actor->Server"  (cost=0.00..1.37 rows=37 width=520) (never executed)
         ->  Index Scan using actor_image_actor_id_type_width on "actorImage" "VideoChannel->Actor->Avatars"  (cost=0.28..8.30 rows=1 width=175) (never executed)
               Index Cond: (("actorId" = "VideoChannel->Actor".id) AND (type = 1))
   ->  Index Scan using thumbnail_video_playlist_id on thumbnail "Thumbnail"  (cost=0.28..8.30 rows=1 width=198) (never executed)
         Index Cond: ("videoPlaylistId" = "VideoPlaylistModel".id)
 Planning Time: 3.750 ms
 JIT:
   Functions: 88
   Options: Inlining false, Optimization false, Expressions true, Deforming true
   Timing: Generation 12.625 ms, Inlining 0.000 ms, Optimization 5.447 ms, Emission 67.502 ms, Total 85.574 ms
 Execution Time: 268.774 ms
(60 rows)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants