web-dev-qa-db-fra.com

Rangée avec dernier horodatage

Comment obtenir la ligne avec la dernière valeur dans A TIMESTAMPZ colonne? Un index est-il nécessaire? Un index change-t-il la stratégie? Le comportement varierait-il de la base de données (j'utilise Postgres 9.4)?

Mon application enregistre les données d'un flux de données. Un autre processus est sans cesse des requêtes pour obtenir la dernière entrée la plus récente. Les données plus anciennes peuvent apparaître à l'occasion des sources secondaires. Donc, les rangées les plus récentes insérées sont généralement, mais pas nécessairement, les données les plus fraîches.

J'utilise ce genre de SQL où when_ est un TIMESTAMP WITH TIME ZONE colonne:

SELECT *
FROM my_table_ 
ORDER BY when_ DESC
LIMIT 1
;

Ce code fonctionne (si aucune valeur nulle dans les données!). Mais avec une éventuelle million de lignes, et une requête toutes les 10 secondes, je suis préoccupé par la performance.

Sans aucun index sur when_ colonne, cette déclaration nécessite-t-elle une analyse complète de toutes les lignes?

L'ajout d'un index change-t-il la performance? Va postgres scannera automatiquement l'index pour localiser la ligne la plus récente ou dois-je faire quelque chose pour faire une analyse d'index?

Avec un index sur when_ Colonne, devrais-je modifier ce SQL pour utiliser une autre approche/stratégie de requête?

Y a-t-il une autre façon de rassembler des rangées fraîchement insérées? J'utilise [~ # ~ # ~] uuid [~ # ~ ~] plutôt que Types de série Pour ma clé principale, et peut fédérer des données entre plusieurs instances de base de données, de sorte que les règles Vérification des nombres d'entier croissants.

2
Basil Bourque

Réponses de base

Puisque vous sélectionnez quelques grandes colonnes (info dans le commentaire) A Scan d'index uniquement est probablement non une option viable.

Ce code fonctionne (si aucune valeur nulle dans les données!)

Ajouter NULLS LAST Pour le faire fonctionner Dans tous les cas, même avec des valeurs null. La clause ajoutée ne fera pas de mal dans les deux sens. Idéalement, utilisez également la clause de l'indice d'accompagnement:

SELECT <some big columns>
FROM   my_table_ 
ORDER  BY when_ DESC NULLS LAST
LIMIT  1;

Sans aucun index sur when_ colonne, cette déclaration nécessite-t-elle une analyse complète de toutes les lignes?

Oui. Sans index, il ne reste plus d'autre option.

Avec un index sur when_ Colonne, devrais-je modifier ce SQL pour utiliser une autre approche/stratégie de requête?

Fondamentalement, c'est la requête parfaite. Il y a plus d'options en combinaison avec l'indexation avancée:

Technique avancée

Vous avez un afflux constant de lignes avec plus tard when_. En supposant que la dernière _when augmente constamment et jamais (ni rarement) diminue (Dernières lignes supprimées/mises à jour), vous pouvez utiliser un très petit Index partiel.

Mise en œuvre de base:

  1. Exécutez votre requête une fois pour récupérer la dernière when_, déduire une marge sûre (pour être en sécurité contre la perte des dernières lignes) et construire une fonction IMMUTABLE autour de lui. Fondamentalement une "fausse constante globale":

    CREATE OR REPLACE FUNCTION f_latest_when()
      RETURNS timestamptz LANGUAGE sql COST 1 IMMUTABLE AS
    $$SELECT timestamptz '2015-07-25 01:00+02'$$;
  2. Créez une index partielle excluant toutes les lignes plus anciennes (moins une marge sûre si nécessaire):

    CREATE INDEX my_table_when_idx ON my_table_ (when_ DESC NULLS LAST)
    WHERE when_ > f_latest_when();

    Avec des millions de lignes, la différence de taille peut être dramatique.

  3. Utilisez la fonction dans toutes vos requêtes associées. Inclure la même chose WHERE condition (redondante si nécessaire) pour convaincre le planificateur de requête que l'index est applicable). Pour la simple requête:

    SELECT <some big columns>
    FROM   my_table_ 
    WHERE when_ > f_latest_when()
    ORDER  BY when_ DESC NULLS LAST
    LIMIT  1;

La taille de l'indice grandit avec de nouvelles entrées (ultérieures). Recréez la fonction avec un horodatage ultérieur et REINDEX à des moments opportuns sans un accès simultané. Seul Reindex, après qu'un nombre de lignes pertinent a été ajouté. Quelques milliers d'entrées ne compteront généralement pas beaucoup. Nous faisons cela pour couper Millions.
[.____] La beauté de celui-ci: les requêtes n'ont pas à changer du tout.

Mise en œuvre avancée avec fonction pour mettre à jour l'index partiel automatiquement dans cette réponse connexe sur SO:

Étroitement liés, avec des conseils plus généraux:

4
Erwin Brandstetter