2009-08-02 6 views
4

(PostreSQL 8.2, en cours d'exécution sur Windows XP)La meilleure façon de « matérialiser vue »

J'ai beaucoup de ces complexes requêtes qui prend plusieurs secondes pour exécuter chacun. Ils ne sont pas des "vues" en réalité, mais peuvent être traités comme tels.

J'ai décidé de conserver les enregistrements de résultat de ces "vues" dans des tables, que j'appelle des tables "auxiliaires".

Je peux garantir qu'il n'y a pas de changement de données après le calcul des tables "aux".

Prenons un exemple:

Supose J'ai une requête « X », donc je persiste c'est des résultats dans « Table_X ». Le jeu d'enregistrements est quelque chose comme ceci:

PERSON*  FIELD_A*  FIELD_ B   FIELD_C 
======================================================= 
1   10   Value1   Value2 
1   20   Value3   Value4 
1   30   Value5   Value6 
------------------------------------------------------ 
2   10   Value1   Value2 
2   20   Value3   Value4 
------------------------------------------------------ 
3   20   Value3   Value4 
3   30   Value5   Value6 
------------------------------------------------------ 
etc.. 

(*)Primary key is: person, field_a 

Comme vous pouvez le voir, chaque « personne » a son sous-ensemble d'enregistrements dans ce tableau. Donc, je peux aller chercher rapidement ses enregistrements avec "select * from table_x where person = <person>".

Je chercherai toujours SEULEMENT par <person>, et toutes mes requêtes ont le même "visage": "PERSON" + Some_Fields. IMPORTANT: Toutes les tables «aux» peuvent être lues (évidemment, avec de «vieilles» données jusqu'à ce que je m'engage) par d'autres transactions pendant que je les «renseigne». Mais je peux garantir qu'ils ne sont jamais mis à jour par ces transactions.

Mon processus actuel est:

- START TRANSACTION; 
    - DO A LOTS OF OPERATIONS ON DATABASE. INSERT/UPDATE/DELETE ON SEVERAL TABLES. 
    - AFTER THAT, I WILL CALCULATE "AUX" TABLES 
    - LOOP THROUGH ALL MY "QUERIES": (WHERE HERE WE CAN CALL AS "X") 
    - LOOP TROUGHT ALL "PERSON": (WHERE HERE WE CAN CALL AS <person>) 
     - DELETE FROM <TABLE_X> WHERE PERSON = <person>; 
     - INSERT INTO <TABLE_X> (PERSON, FIELD_A, FIELD_B, FIELD_C) 
           (SELECT <person>, 
             FIELDS... 
           FROM "LOTS OF TABLES" 
           JOIN "COMPLEX SQL"... 
           WHERE SOME_FIELD = <person> 
          ); 
    - END LOOP "PERSON" 
    - END LOOP "QUERIES" 
- COMMIT; 

Considérations:

Certains de ces tableaux a des milliers de dossiers, et souvent seulement quelques dossiers ont besoin d'être mise à jour/supprimer/insérer si la comparaison avec le jeu d'enregistrements déjà "existant" dans la table. Comme la suppression et le "réinsertion" causent trop de "disque i/o" (si évident), et que j'ai besoin de "mettre à jour" juste quelques enregistrements, j'essaye d'obtenir une manière efficace de faire il. J'ai essayé de supprimer/mettre à jour/insérer dans des étapes séparées, le faire directement à partir de "requête complexe", mais cela prend trop de temps, car la requête a été exécutée 3 fois (une fois pour supprimer et une autre).

Des suggestions?

Répondre

2

Avant cela, avez-vous exécuté un plan d'explication sur votre requête complexe et ajouté des index pour l'améliorer?

Si vous devez le faire, oubliez toutes les conneries en boucle; rien de ce que vous faites ne sera plus optimisé que le code interne C et le code d'assemblage de la base de données. Il suffit d'écrire une vue et de la matérialiser si nécessaire, en sélectionnant * dans une table. Dans de nombreux cas, cela sera plus rapide que de boucler, supprimer et insérer.

+0

D'accord, faire la requête aussi vite que possible avant de vous engager dans cette voie. La vue matérialisée peut se compliquer rapidement si vous devez les tenir à jour avec les données actuelles. Voir http://www.pgcon.org/2008/schedule/events/69.en.html pour de bonnes informations. – AngerClown

Questions connexes