Projet

Général

Profil

Development #54747

Déléguer le calcul de Event.full à la base de donnée

Ajouté par Valentin Deniaud il y a presque 3 ans. Mis à jour il y a plus de 2 ans.

Statut:
Fermé
Priorité:
Normal
Assigné à:
Catégorie:
-
Version cible:
-
Début:
Echéance:
% réalisé:

0%

Temps estimé:
Patch proposed:
Oui
Planning:
Non

Description

Par exemple en utilisant un trigger, ça concerne également Event.almost_full.

(utile notamment pour simplifier la réservation en masse introduite par #54332, où des annotations compliquées sont nécessaires pour maintenir ces flags)


Fichiers


Demandes liées

Suit Chrono - Development #56148: Supprimer les références à sqliteFermé13 août 2021

Actions

Révisions associées

Révision 0b53360c (diff)
Ajouté par Lauréline Guérin il y a plus de 2 ans

agendas: trigger full and places event fields (#54747)

Historique

#1

Mis à jour par Valentin Deniaud il y a presque 3 ans

Je vois deux voies :
  • soit on traduit vraiment ce qu'on fait actuellement en django en SQL, genre à chaque fois qu'un booking est créé, compter le nombre de bookings de l'évènements et en déduire full (et donc la création d'un booking entraîne toujours une requête count)
  • soit on crée un nouveau champ booking_count sur un évènement, on fait +1/-1 si un booking est créé/annulé et on met full à jour à partir de booking_count

J'ai envie de partir sur l'option 2 mais comme j'y connais rien je pose ça ici.

#2

Mis à jour par Lauréline Guérin il y a presque 3 ans

ça se gère très bien à coup de trigger + champ readonly côté django pour éviter les surcharges par erreur; je peux proposer un truc à l'occasion
(j'ai déjà écrit des trucs comme ça par le passé)

#3

Mis à jour par Valentin Deniaud il y a presque 3 ans

Ça roule, je te le laisse volontiers !

#4

Mis à jour par Lauréline Guérin il y a plus de 2 ans

  • Assigné à mis à Lauréline Guérin
#5

Mis à jour par Lauréline Guérin il y a plus de 2 ans

  • Echéance mis à 16 août 2021
  • Début changé de 10 juin 2021 à 16 août 2021
  • Suit Development #56148: Supprimer les références à sqlite ajouté
#6

Mis à jour par Lauréline Guérin il y a plus de 2 ans

  • Echéance 16 août 2021 supprimé
  • Début 16 août 2021 supprimé
#7

Mis à jour par Lauréline Guérin il y a plus de 2 ans

Pour simplifier les triggers, et aussi parce qu'on utilise souvent cette information (qu'on va chercher à coup d'annotations), j'ai ajouté des compteurs booked_places et booked_waiting_list_places

On pourrait simplifier encore un peu les triggers, et surtout les déclencher moins souvent, en ajoutant une app comme django-readonly-field (https://pypi.org/project/django-readonly-field/), qui garantirait que les compteurs et les bool full/almost_full ne sont pas modifiés par le code.
Mais ça fait une contrib de plus à intégrer.

#8

Mis à jour par Benjamin Dauvergne il y a plus de 2 ans

  • Statut changé de Solution proposée à Solution validée

Lauréline Guerin a écrit :

Pour simplifier les triggers, et aussi parce qu'on utilise souvent cette information (qu'on va chercher à coup d'annotations), j'ai ajouté des compteurs booked_places et booked_waiting_list_places

On pourrait simplifier encore un peu les triggers, et surtout les déclencher moins souvent, en ajoutant une app comme django-readonly-field (https://pypi.org/project/django-readonly-field/), qui garantirait que les compteurs et les bool full/almost_full ne sont pas modifiés par le code.

Je ne comprends pas très bien comment ça ferait pour ne pas déclencher le trigger sur event ? Dès qu'il y aura un update même partiel il est déclenché, non ? Pour moi les déclenchements des triggers ne coûtent pas trop cher de toute façon, sauf s'ils se mettent à écrire d'autres lignes que celles qu'on est en train de modifier ou font des SELECT un peu complexe.

Mais ça fait une contrib de plus à intégrer.

Le seul cas d'amplification d'écriture qui me parait possible c'est sur le

    SET
        booked_places = (
            SELECT COUNT(*) FROM agendas_booking b
            WHERE b.event_id = e_id AND b.cancellation_datetime IS NULL AND b.in_waiting_list = false
        ),
        booked_waiting_list_places = (
            SELECT COUNT(*) FROM agendas_booking b
            WHERE b.event_id = e_id AND b.cancellation_datetime IS NULL AND b.in_waiting_list = true
        )
    WHERE id = e_id;

si vraiment tu veux améliorer ça tu pourrais rajouter une condition au where et utiliser des CTEs:

WITH
        booked_places AS (
            SELECT COUNT(*) AS cnt FROM agendas_booking b
            WHERE b.event_id = e_id AND b.cancellation_datetime IS NULL AND b.in_waiting_list = false
        ),
        booked_waiting_list_places AS (
            SELECT COUNT(*) AS cnt FROM agendas_booking b
            WHERE b.event_id = e_id AND b.cancellation_datetime IS NULL AND b.in_waiting_list = true
        )
    UPDATE agendas_event
    SET
        booked_places = booked_places.cnt,
        booked_waiting_list_places = booked_waiting_list_places.cnt
    FROM booked_places, booked_waiting_list_places
    WHERE id = e_id AND (agendas_event.booked_places <> booked_places.cnt OR agendas_event.booked_waiting_list_places <> booked_waiting_list_places.cnt)

Mais vraiment ça ne me parait pas critique (à moins qu'il y ait énormément d'écritures sur les lignes de agendas_booking sans rapport avec les places et les listes d'attente).


Ça me parait donc super mais vu que ça touche quand même à une mécanique complexe je veux bien un autre survol.

#9

Mis à jour par Lauréline Guérin il y a plus de 2 ans

Amélioration des triggers (CTE et SELECT INTO)

Je ne comprends pas très bien comment ça ferait pour ne pas déclencher le trigger sur event ?

Si on a la garantie que les champs booked_places, booked_waiting_list_places, full et almost_full ne sont jamais écrasés par chrono, alors on peut se passer du recalcul des compteurs places dans la fonction update_event_full_fields
On peut aussi conditionner le déclenchement de update_event_full_fields_trigger aux changements de valeur de booked_places, booked_waiting_list_places, places et waiting_list_places seulement.
Et le déclenchement de update_event_places_fields_trigger à update avec changement de valeur de in_waiting_list ou cancellation_datetime, insert et delete seulement.

Je ne pense pas non plus qu'il y ait tant de mouvements que cela sur les tables event et booking. Je préfère éviter d'introduire une nouvelle dépendance pour le moment.

si vraiment tu veux améliorer ça tu pourrais rajouter une condition au where et utiliser des CTEs

J'ai fait ça, au moins pour éviter de déclencher update_event_full_fields_trigger sur l'anonymisation des réservations.

#11

Mis à jour par Benjamin Dauvergne il y a plus de 2 ans

  • Statut changé de Solution proposée à Solution validée

Toujours ok pour moi.

#12

Mis à jour par Frédéric Péters il y a plus de 2 ans

Sur l'SQL en lui-même je n'ai pas de commentaire mais sur la structure du projet je me demande si ce code pourrait être posé différemment que dans une longue chaine, on pourrait peut-être avoir le code dans un chrono/agendas/sql/update_event_triggers.sql, ou autre nom ou emplacement, il y a peut-être déjà des pratiques existantes. Ça permettrait déjà d'y avoir une coloration syntaxique.

#13

Mis à jour par Lauréline Guérin il y a plus de 2 ans

j'ai laissé le sql revert dans la migration (peu de lignes)

#14

Mis à jour par Valentin Deniaud il y a plus de 2 ans

  • Statut changé de Solution proposée à Solution validée
#15

Mis à jour par Lauréline Guérin il y a plus de 2 ans

  • Statut changé de Solution validée à Résolu (à déployer)
commit 0b53360c0c5eaa08c5d3ec0339e430e106d340d9
Author: Lauréline Guérin <zebuline@entrouvert.com>
Date:   Mon Aug 16 15:59:01 2021 +0200

    agendas: trigger full and places event fields (#54747)
#16

Mis à jour par Frédéric Péters il y a plus de 2 ans

  • Statut changé de Résolu (à déployer) à Solution déployée

Formats disponibles : Atom PDF