Actualiser progressivement la vue matérialisée dans PostgreSQL
33
Est-il possible d'actualiser une vue matérialisée de manière incrémentielle dans PostgreSQL, c'est-à-dire uniquement pour les données nouvelles ou modifiées?
Périodiquement, de nouvelles valeurs sont ajoutées graphou une valeur existante est mise à jour. Je souhaite actualiser la vue graph_avgtoutes les deux heures uniquement pour les valeurs mises à jour. Cependant, dans PostgreSQL 9.3, la table entière est actualisée. Ceci prend beaucoup de temps. La prochaine version 9.4 autorise la CONCURRENTmise à jour mais actualise toujours la vue entière. Avec des centaines de millions de lignes, cela prend quelques minutes.
Quel est un bon moyen de garder trace des nouvelles valeurs et de ne mettre à jour que partiellement la vue?
Vous pouvez toujours implémenter votre propre table servant de "vue matérialisée". C'est ce que vous deviez faire avant MATERIALIZED VIEWétait implémenté dans Postgres 9.3 de toute façon.
(Ou utilisez SELECTdirectement l' instruction, sans créer de VIEW.)
Ensuite, en fonction des détails non divulgués de votre cas d'utilisation, vous pouvez DELETE/ UPDATE/ INSERTmodifier les modifications manuellement.
Une instruction DML de base avec des CTE modifiant les données pour votre table en l'état :
En supposant que personne d' autre ne tente d' écrire à en graph_avgmême temps (lecture est pas un problème):
WITH del AS(DELETEFROM graph_avg tWHERENOTEXISTS(SELECT1FROM graph_avg_view v WHERE v.xaxis = v.xaxis);), upd AS(UPDATE graph_avg tFROM graph_avg_view vWHERE t.xaxis = v.xaxisAND t.avg_val <> v.avg_val)INSERTINTO graph_avg tSELECT*FROM graph_avg_view vLEFTJOIN graph_avg t USING(xaxis)WHERE t.xaxis ISNULL;
Mais cela devrait probablement être optimisé.
Recette de base:
Ajouter une timestampcolonne avec défaut now()à votre table de base. Appelons ça ts.
Si vous avez des mises à jour, ajoutez un déclencheur pour définir l'horodatage actuel avec chaque mise à jour modifiant l'un xaxisou l' autre value.
Créez un petit tableau pour vous rappeler l'horodatage de votre dernier instantané. Appelons ça mv:
CREATETABLE mv (
tbl text PRIMARYKEY, ts timestamp NOTNULLDEFAULT'-infinity');-- possibly more details
Créez cet index partiel multicolonne:
CREATEINDEX graph_mv_latest ON graph (xaxis, value)WHERE ts >='-infinity';
Utilisez l'horodatage du dernier instantané en tant que prédicat dans vos requêtes pour actualiser celui-ci avec une utilisation d'index parfaite.
À la fin de la transaction, supprimez l'index et recréez-le avec l'horodatage de la transaction en remplaçant l'horodatage dans le prédicat d'index (initialement '-infinity'), que vous avez également enregistré dans votre table. Tout en une transaction.
Notez que l'index partiel est génial pour couvrir INSERTet les UPDATEopérations, mais pas DELETE. Pour couvrir cela, vous devez considérer l'ensemble du tableau. Tout dépend des exigences exactes.
Merci pour la clarté des points de vue matérialisés et pour avoir suggéré une autre réponse.
user4150760
13
Mise à jour simultanée (Postgres 9.4)
Bien qu'il ne s'agisse pas d'une mise à jour incrémentielle comme vous l'avez demandé, Postgres 9.4 fournit une nouvelle fonctionnalité de mise à jour simultanée .
Pour citer le doc…
Avant PostgreSQL 9.4, actualiser une vue matérialisée signifiait verrouiller l’ensemble de la table, empêchant ainsi toute interrogation de celle-ci. bloque les requêtes suivantes. Cela peut maintenant être atténué avec le mot clé CONCURRENTLY:
Un index unique devra cependant exister sur la vue matérialisée. Au lieu de verrouiller la vue matérialisée, il en crée une version mise à jour temporaire, compare les deux versions, puis applique les actions INSERT et DELETE à la vue matérialisée pour appliquer la différence. Cela signifie que les requêtes peuvent toujours utiliser la vue matérialisée pendant sa mise à jour. Contrairement à sa forme non concurrente, les n-uplets ne sont pas figés, et il faut VACUUMing en raison de la suppression de SUPPLÉ mentionnée ci-dessus qui laissera des nuplets morts.
Cette mise à jour simultanée effectue toujours une nouvelle requête complète (non incrémentielle). Donc, de manière concourante, vous ne gagnez pas du temps de calcul global, cela minimise simplement le temps pendant lequel votre vue matérialisée n'est pas disponible pour être utilisée lors de sa mise à jour.
Pendant un moment, j'étais excité jusqu'à ce que je lise attentivement. it instead creates a temporary updated version of it...compares the two versions- Cela signifie que la version mise à jour temporaire est toujours un calcul complet, puis applique la différence à la vue existante. Donc, essentiellement, je suis encore en train de refaire TOUS les calculs, mais juste dans la table temporaire.
user4150760
5
Ah, vrai, CONCURRENTLYn’économise pas sur le temps de calcul global, il minimise simplement le temps pendant lequel votre vue matérialisée n’est pas disponible pendant sa mise à jour.
Mise à jour simultanée (Postgres 9.4)
Bien qu'il ne s'agisse pas d'une mise à jour incrémentielle comme vous l'avez demandé, Postgres 9.4 fournit une nouvelle fonctionnalité de mise à jour simultanée .
Pour citer le doc…
Cette mise à jour simultanée effectue toujours une nouvelle requête complète (non incrémentielle). Donc, de manière concourante, vous ne gagnez pas du temps de calcul global, cela minimise simplement le temps pendant lequel votre vue matérialisée n'est pas disponible pour être utilisée lors de sa mise à jour.
la source
it instead creates a temporary updated version of it...compares the two versions
- Cela signifie que la version mise à jour temporaire est toujours un calcul complet, puis applique la différence à la vue existante. Donc, essentiellement, je suis encore en train de refaire TOUS les calculs, mais juste dans la table temporaire.CONCURRENTLY
n’économise pas sur le temps de calcul global, il minimise simplement le temps pendant lequel votre vue matérialisée n’est pas disponible pendant sa mise à jour.