Project

General

Profile

Développement #54747

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

Added by Valentin Deniaud over 3 years ago. Updated over 3 years ago.

Status:
Fermé
Priority:
Normal
Category:
-
Target version:
-
Start date:
Due date:
% Done:

0%

Estimated time:
Patch proposed:
Yes
Planning:
No

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)


Files


Related issues

Follows Chrono - Développement #56148: Supprimer les références à sqliteFermé13 August 2021

Actions

Associated revisions

Revision 0b53360c (diff)
Added by Lauréline Guérin over 3 years ago

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

History

#1

Updated by Valentin Deniaud over 3 years ago

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

Updated by Lauréline Guérin over 3 years ago

ç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

Updated by Valentin Deniaud over 3 years ago

Ça roule, je te le laisse volontiers !

#4

Updated by Lauréline Guérin over 3 years ago

  • Assignee set to Lauréline Guérin
#5

Updated by Lauréline Guérin over 3 years ago

  • Due date set to 16 August 2021
  • Start date changed from 10 June 2021 to 16 August 2021
  • Follows Développement #56148: Supprimer les références à sqlite added
#6

Updated by Lauréline Guérin over 3 years ago

  • Due date deleted (16 August 2021)
  • Start date deleted (16 August 2021)
#7

Updated by Lauréline Guérin over 3 years ago

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

Updated by Benjamin Dauvergne over 3 years ago

  • Status changed from Solution proposée to 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

Updated by Lauréline Guérin over 3 years ago

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

Updated by Benjamin Dauvergne over 3 years ago

  • Status changed from Solution proposée to Solution validée

Toujours ok pour moi.

#12

Updated by Frédéric Péters over 3 years ago

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

Updated by Lauréline Guérin over 3 years ago

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

#14

Updated by Valentin Deniaud over 3 years ago

  • Status changed from Solution proposée to Solution validée
#15

Updated by Lauréline Guérin over 3 years ago

  • Status changed from Solution validée to 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

Updated by Frédéric Péters over 3 years ago

  • Status changed from Résolu (à déployer) to Solution déployée

Also available in: Atom PDF