Traewelling / traewelling

Free check-in service to log your public transit journeys
https://traewelling.de
GNU Affero General Public License v3.0
224 stars 43 forks source link

:zap: sort by real departure and query optimization #2703

Open MrKrisKrisu opened 1 week ago

MrKrisKrisu commented 1 week ago

fixes #1382

MrKrisKrisu commented 1 week ago

Noch nicht ganz fertig... das globale Dashboard sortiert jetzt primär nach Echtzeitdaten, das macht an der Performance durch die letzten DB-Änderungen nichts mehr aus. Den Query hab ich auch so umgeschrieben, dass wir primär Joins nutzen, was die Execution in meinem Fall von 30-40 Sekunden auf nur 40 MILLIsekunden drückt.

Habe gerade nur noch das Problem, dass die Sortierung einen temporary table und filesort macht. Bin aber leider zu sehr MariaDB/MySQL Noob um da gerade eine Lösung parat zu haben... Der Unterschied mit und ohne Sort beträgt 20 Sekunden +-.

t

MrKrisKrisu commented 1 week ago

Das "ALL" bei Users stört mich auch etwas, aber es gibt eigentlich keinen Index mehr der das ändert. Man könnte noch id, private_profile hinzufügen, der ändert aber nichts an der Performance.

MrKrisKrisu commented 1 week ago
SELECT `statuses`.*
FROM   `statuses`
       INNER JOIN `train_checkins`
               ON `train_checkins`.`status_id` = `statuses`.`id`
       INNER JOIN `train_stopovers` AS `origin_stopover`
               ON `train_checkins`.`origin_stopover_id` = `origin_stopover`.`id`
       INNER JOIN `users`
               ON `statuses`.`user_id` = `users`.`id`
       LEFT JOIN `user_mutes`
              ON `user_mutes`.`muted_id` = `users`.`id`
                 AND `user_mutes`.`user_id` = 1
       LEFT JOIN `user_blocks` AS `blocked_users`
              ON `blocked_users`.`blocked_id` = `users`.`id`
                 AND `blocked_users`.`user_id` = 1
       LEFT JOIN `user_blocks` AS `blocked_by_users`
              ON `blocked_by_users`.`user_id` = `users`.`id`
                 AND `blocked_by_users`.`blocked_id` = 1
       LEFT JOIN `follows`
              ON `follows`.`follow_id` = `users`.`id`
                 AND `follows`.`user_id` = 1
WHERE  `user_mutes`.`id` IS NULL
       AND `blocked_users`.`id` IS NULL
       AND `blocked_by_users`.`id` IS NULL
       AND ( ( `users`.`private_profile` = 0
               AND `visibility` IN ( 0, 4 ) )
              OR `users`.`id` = 1
              OR ( `follows`.`id` IS NOT NULL
                   AND `statuses`.`visibility` NOT IN ( 1, 3 ) ) )
       AND `origin_stopover`.`departure_real` < '2024-06-24 23:59'
ORDER  BY `origin_stopover`.`departure_real` DESC,
          `origin_stopover`.`departure_planned` DESC
HerrLevin commented 1 week ago

Irgendwas stimmt mit der Query aktuell noch nicht. Ich sehe gerade nur meine Check-Ins im (global) dashboard.

Ganz komisch ist auch noch, dass die Tests gerade nicht Alarm schlagen?!

(Aber ansonsten ziemlich nice bis jetzt!)

HerrLevin commented 1 week ago

Irgendwas stimmt mit der Query aktuell noch nicht. Ich sehe gerade nur meine Check-Ins im (global) dashboard.

Es waren Check-Ins ohne Live-Daten. Fällt im Live-Datensatz seltener auf, aber mit geseedeten Testdaten schon.

@MrKrisKrisu Es bräuchte ne Erweiterung der Tests auf Dashboard mit fehlenden Live-Daten. :)

SELECT `statuses`.*, `origin_stopover`.`departure_real`, `origin_stopover`.`departure_planned`
FROM `statuses`
         INNER JOIN `train_checkins`
                    ON `train_checkins`.`status_id` = `statuses`.`id`
         INNER JOIN `train_stopovers` AS `origin_stopover`
                    ON `train_checkins`.`origin_stopover_id` = `origin_stopover`.`id`
         INNER JOIN `users`
                    ON `statuses`.`user_id` = `users`.`id`
         LEFT JOIN `user_mutes`
                   ON `user_mutes`.`muted_id` = `users`.`id`
                       AND `user_mutes`.`user_id` = 1
                       AND `user_mutes`.`id` IS NULL
         LEFT JOIN `user_blocks` AS `blocked_users`
                   ON `blocked_users`.`blocked_id` = `users`.`id`
                       AND `blocked_users`.`user_id` = 1
                       AND `blocked_users`.`id` IS NULL
         LEFT JOIN `user_blocks` AS `blocked_by_users`
                   ON `blocked_by_users`.`user_id` = `users`.`id`
                       AND `blocked_by_users`.`blocked_id` = 1
                       AND `blocked_by_users`.`id` IS NULL
         LEFT JOIN `follows`
                   ON `follows`.`follow_id` = `users`.`id`
                       AND `follows`.`user_id` = 1
WHERE (
    (`users`.`private_profile` = 0 AND `visibility` IN (0, 4))
        OR `users`.`id` = 1
        OR (`follows`.`id` IS NOT NULL AND `statuses`.`visibility` NOT IN (1, 3)))
  AND (
    `origin_stopover`.`departure_real` < '2024-06-27 23:59'
        OR (
        `origin_stopover`.`departure_real` IS NULL
            AND `origin_stopover`.`departure_planned` < '2024-06-27 23:59')
    )
ORDER BY `origin_stopover`.`departure_real` DESC,
         `origin_stopover`.`departure_planned`