0
votes

Améliorer la vitesse de jointure sur la gamme horodatale sur PostgreSQL

J'ai une requête qui rejoint deux tables:

  • TABLEAU 1 DATA a une colonne TIMESTAMP
  • TABLEAU 2 COMMANDES A Démarrer et mettre fin à des colonnes horodaques

    sur la table 1 J'ai un index sur la colonne TIMESTAMP et sur la table 2, j'ai un index sur Démarrer | Fin (dans cet ordre). Tout fonctionne bien et est rapide lorsque je les rejoints simplement comme de d joink o sur d.timestamp> O.Start_ts et d.timetamp <= o.end_ts

    Le problème est que lorsqu'une commande n'est pas terminée, le end_ts est NULL, donc j'ai besoin de modifier ma jointure à d.timestamp <= coalesce (o.end_ts, null) , de la Expliquez que je peux voir que maintenant l'analyse de l'index inclut une section filtre qui rend la course plus lente (de 1 à 14 ans).

    La requête que j'utilise actuellement est la suivante: xxx

    L'expliquer est xxx


4 commentaires

S'il vous plaît Modifier Votre question et ajoutez le plan d'exécution généré à l'aide d'utiliser Expliquer (analyser, tampon, texte de format) < / b> ( pas juste une "simple" expliquer) comme texte formaté et assurez-vous d'empêcher la indentation du plan. Collez le texte, puis mettez `` ` sur la ligne avant le plan et sur une ligne après le plan. Veuillez également inclure les instructions complètes Créer index pour tous les index.


@Belisto Le même résultat, les timings et expliquer sont les mêmes


Essayez .. sur d.timestamp> O.Start_ts et d.TimeStamp <= o.end_ts Union Tout .. sur PD.TMESTAMP> O.Start_time et O.end_time est null


@Sserg qui fonctionne parfaitement pour une simple requête comme celle-ci, mais dans une requête avec des jointures et des clauses de groupe, un syndicat rendrait la requête beaucoup plus longue


3 Réponses :


0
votes

Merci à Incognito sur IRC J'ai trouvé une solution viable, créez un index comme celui-ci: xxx

et modifier la requête en PD. horodatage <= coalesce (o.end_time, "infini") . De cette façon, j'ai toujours la valeur nullable et j'ai une valeur indexée que je peux utiliser, car je ne pouvais pas indexer le maintenant () car il est variable


4 commentaires

Cela n'est pas équivalent aux exigences énoncées. Plus de rangées pourraient être retournées.


@Serg pourquoi? Dans mon cas, lorsque l'ordre final est NULL signifie qu'il n'est pas terminé, alors l'infini fonctionnerait car c'est toujours plus grand que maintenant ()


"Infinity .. toujours plus grand que maintenant ()" signifie que plus de rangées pourraient être retournées. Vous devez probablement affiner la question concernant votre utilisation de maintenant () . Était-ce une requête ou autre chose?


@Sserg Je pense que c'est juste parce que la table n'a jamais contient des données de l'avenir, il n'y aura donc pas de données avec un horodatage supérieur à maintenant ()



2
votes

Ceci est l'un des cas où Types de gamme est utile comme Ils traitent correctement les valeurs nulles.

Créer un index sur la plage: xxx

puis utilisez la même plage définition dans la condition de jointure xxx < / Pré>


non liée, mais: j'utiliserais pd.timetamp <'2019-09-22 22:00:00' au lieu d'un <= Opérateur avec un horodatage qui est quelques millisecondes avant 22h00:00


7 commentaires

Je suis d'accord sur la partie non liée, concernant l'index, pourquoi gist?


@ Alex88: Seul un index GIST prend en charge l'opérateur <@ sur les gammes


Votre start_time , end_time peut être remplacé par une colonne à une seule gamme, de cette façon, vous n'auriez jamais besoin de vous inquiéter de la manière de représenter des gammes "sans bornes" comme cela fait partie de la valeur de colonne elle-même.


cela aurait un sens, j'ai juste besoin de vérifier comment la bibliothèque de la DB utilisée le soutient


Je pense que le seul inconvénient de cela, c'est que nous ne pouvons pas facilement modifier l'inclusion / exclusion des limites sur la requête sans changer l'index


@ Alex88: Mais ne veut-ils pas toujours dire la même chose? Cela me semble étrange que la règle des limites inclusives / exclusives change de manière aléatoire. Mais si vous avez besoin de cela, une colonne à une seule gamme où ces informations sont stockées avec la valeur elle-même résoudraient le problème. L'index n'a alors besoin que de mentionner la colonne, et non de créer une nouvelle gamme.


Il ne change en fait que lorsque de l'autre côté de la relation la valeur est un agrégat et est lié à la minute précédente ou suivante, mais c'est juste une question de normalisation



1
votes

Vous pouvez éviter la manipulation spéciale des NULLS en utilisant non (nié_condition) code>. (Mais la solution Infinity code> est plus propre, IMO)


SELECT *
FROM data pd
JOIN orders o ON pd.timestamp > o.start_time 
        AND NOT(pd.timestamp > o.end_time )
WHERE pd.machine_id = 19 
        AND pd.name = 'somevalue'
        AND pd.timestamp > '2019-09-15 22:00:00'
        AND pd.timestamp <= '2019-09-22 21:59:59.999'
        ;


1 commentaires

Cela a l'air bien aussi, je n'ai pas encore essayé de voir comment la requête explique le gère, mais cela pourrait éviter d'avoir des fonctions dans l'index