0
votes

Comment optimiser cette sélection

SELECT *
FROM   trips,
       dates
WHERE  places_number_on_flag > 0
       AND places_number > 0
       AND ( places_number - ( (SELECT Count(id)
                                FROM   resrv_customers
                                WHERE  trip = trips.id
                                       AND ow > 0)
                               + (SELECT Count(id)
                                  FROM   resrv_customers
                                  WHERE  trip = trips.id
                                         AND extra_seat = 1
                                         AND ow > 0) ) < 20 )
       AND dates.id = trips.trip_date
       AND dates.from_date > 2458553;  
It returns 5 rows after about a minute and 50 seconds.I want it to be faster.

4 commentaires

Avez-vous consulté le plan d'exécution?


Veuillez afficher le tableau Créer le tableau et Créer une index Index plus le plan. Vous devez également retravailler la requête en utilisant une syntaxe de jointure explicite pour une meilleure lisibilité.


@dodekja. . . Vous devez expliquer quelle logique la requête met en œuvre.


Mauvaises habitudes de frappe: Utiliser des jointures de style anciennes - que la liste des tables Séparation des virgules a été remplacée par le approprié ansi rejoindre Syntaxe dans l'ANSI- 92 SQL Standard ( 25 ans Il y a) et son utilisation est découragée


3 Réponses :


0
votes

Nous pouvons essayer de réécrire votre requête à l'aide d'une jointure à la table resrv_customères , au lieu d'utiliser des sous-requêtes corrélées coûteuses: xxx

indexation ici pourrait être délicate, car Faites un SELECT * . Pour que Postgres utilise n'importe quel index, vous devrez peut-être faire beaucoup de colonnes couvrant, c'est-à-dire créer de grands indices.


1 commentaires

Juste un commentaire sur l'optimisation, ce CTE sera probablement un goulot d'étranglement probablement le processus, car il aura besoin de grouper et de compter tout le tableau resrv_customères , lorsque vous n'avez besoin que de correspondre au "code> trip.id . Aussi ow> 0 pourrait être dans la clause WHERE, puisque les deux comptes le nécessitent, plus en utilisant la clause Filtre ( POSTGRESQL.ORG/DOCS/CURRENT/... ) est généralement plus rapide qu'un cas à l'intérieur d'un compte.



2
votes

Une optimisation serait de ne pas exécuter la sous-requête une fois et d'utiliser une agrégation conditionnelle pour compter les sièges:

SELECT *
FROM   trips
  JOIN dates on dates.id = trips.trip_date
WHERE  places_number_on_flag > 0
       AND places_number > 0
       AND ( places_number - ( (SELECT Count(id) + count(id) filter (where extra_seat = 1)
                                FROM   resrv_customers
                                WHERE  trip = trips.id
                                       AND ow > 0)) < 20 )
       AND dates.from_date > 2458553;  


1 commentaires

J'ajouterais: Utilisez des noms de variables au lieu de "*". Et rappelez-vous, Expliquez Analyser vous aidera à connaître le coût de chaque étape.



0
votes

Essayez ceci:

with rc_count as
(
    select trip, count(*) as ow_count, sum( (extra_seat = 1)::int ) as ow_count_with_extra_seat
    from resrv_customers
    where ow > 0
    group by trip    
)

SELECT *
FROM   trips
join   dates on dates.id = trips.trip_date
join   rc_count rc on trips.id = trip 
WHERE  places_number_on_flag > 0
       AND places_number > 0
       AND dates.from_date > 2458553
       and places_number - (ow_count + ow_count_with_extra_seat) < 20       


2 commentaires

Remarque: cette réponse est presque identique à ce que j'ai posté plus tôt.


@TimbieGeleisen n'a pas remarqué cela. Je me suis concentré sur la rédaction de ma propre réponse et j'ai également déplacé la condition partagée ow> 0 à l'endroit où la clause