MVCC dans PostgreSQL-6. Le vide

Nous avons commencé par des problèmes liés à l' isolement , fait une digression sur la structure des données de bas niveau , puis discuté des versions des lignes et observé comment les instantanés de données sont obtenus à partir des versions des lignes.

La dernière fois, nous avons parlé des mises à jour HOT et de l'aspiration sur la page, et aujourd'hui nous allons procéder à un vulgaris sous vide bien connu. Vraiment, tant de choses ont déjà été écrites à ce sujet que je peux à peine ajouter quelque chose de nouveau, mais la beauté d'une image complète nécessite un sacrifice. Alors, gardez patience.

Le vide


Que fait le vide?


L'aspirateur encart fonctionne rapidement, mais ne libère qu'une partie de l'espace. Il fonctionne dans une page de table et ne touche pas aux index.

Le vide de base "normal" se fait à l'aide de la commande VACUUM, et nous l'appellerons simplement "vacuum" (laissant "autovacuum" pour une discussion séparée).

Le vide traite donc toute la table. Il élimine non seulement les tuples morts, mais aussi les références à eux de tous les index.

L'aspiration est concurrente avec d'autres activités du système. La table et les index peuvent être utilisés de manière régulière à la fois pour les lectures et les mises à jour (cependant, l'exécution simultanée de commandes telles que CREATE INDEX, ALTER TABLE et certaines autres est impossible).

Seules les pages du tableau sont examinées à l'endroit où certaines activités ont eu lieu. Pour les détecter, la carte de visibilité est utilisée (pour vous rappeler, la carte suit les pages qui contiennent de très vieux tuples, qui sont bien sûr visibles dans tous les instantanés de données). Seules les pages traitées ne sont pas suivies par la carte de visibilité et la carte elle-même est mise à jour.

La carte de l'espace libre est également mise à jour dans le processus pour refléter l'espace libre supplémentaire dans les pages.

Comme d'habitude, créons un tableau:

=> CREATE TABLE vac( id serial, s char(100) ) WITH (autovacuum_enabled = off); => CREATE INDEX vac_s ON vac(s); => INSERT INTO vac(s) VALUES ('A'); => UPDATE vac SET s = 'B'; => UPDATE vac SET s = 'C'; 

Nous utilisons le paramètre autovacuum_enabled pour désactiver le processus autovacuum. Nous en discuterons la prochaine fois, et maintenant il est essentiel pour nos expériences que nous contrôlions manuellement l'aspiration.

La table a maintenant trois tuples, chacun étant référencé à partir de l'index:

 => SELECT * FROM heap_page('vac',0); 
  ctid | state | xmin | xmax | hhu | hot | t_ctid -------+--------+----------+----------+-----+-----+-------- (0,1) | normal | 4000 (c) | 4001 (c) | | | (0,2) (0,2) | normal | 4001 (c) | 4002 | | | (0,3) (0,3) | normal | 4002 | 0 (a) | | | (0,3) (3 rows) 

 => SELECT * FROM index_page('vac_s',1); 
  itemoffset | ctid ------------+------- 1 | (0,1) 2 | (0,2) 3 | (0,3) (3 rows) 

Après avoir aspiré, les tuples morts sont aspirés et il ne reste qu'un seul tuple vivant. Et une seule référence reste dans l'index:

 => VACUUM vac; => SELECT * FROM heap_page('vac',0); 
  ctid | state | xmin | xmax | hhu | hot | t_ctid -------+--------+----------+-------+-----+-----+-------- (0,1) | unused | | | | | (0,2) | unused | | | | | (0,3) | normal | 4002 (c) | 0 (a) | | | (0,3) (3 rows) 
 => SELECT * FROM index_page('vac_s',1); 
  itemoffset | ctid ------------+------- 1 | (0,3) (1 row) 

Notez que les deux premiers pointeurs ont acquis le statut «inutilisé» au lieu de «mort», qu'ils acquerront avec un vide sur la page.

À propos de l'horizon de transaction encore une fois


Comment PostgreSQL détermine-t-il quels tuples peuvent être considérés comme morts? Nous avons déjà abordé le concept d'horizon des transactions lors de la discussion des instantanés de données , mais cela ne fera pas de mal de répéter une question aussi importante.

Reprenons l'expérience précédente.

 => TRUNCATE vac; => INSERT INTO vac(s) VALUES ('A'); => UPDATE vac SET s = 'B'; 

Mais avant de mettre à jour la ligne une fois de plus, laissez une autre transaction commencer (mais pas se terminer). Dans cet exemple, il utilisera le niveau de lecture validée, mais il doit obtenir un vrai numéro de transaction (non virtuel). Par exemple, la transaction peut changer et même verrouiller certaines lignes dans n'importe quelle table, pas obligatoire vac :

 | => BEGIN; | => SELECT s FROM t FOR UPDATE; 
 | s | ----- | FOO | BAR | (2 rows) 

 => UPDATE vac SET s = 'C'; 

Il y a maintenant trois lignes dans le tableau et trois références dans l'index. Que se passera-t-il après avoir passé l'aspirateur?

 => VACUUM vac; => SELECT * FROM heap_page('vac',0); 
  ctid | state | xmin | xmax | hhu | hot | t_ctid -------+--------+----------+----------+-----+-----+-------- (0,1) | unused | | | | | (0,2) | normal | 4005 (c) | 4007 (c) | | | (0,3) (0,3) | normal | 4007 (c) | 0 (a) | | | (0,3) (3 rows) 
 => SELECT * FROM index_page('vac_s',1); 
  itemoffset | ctid ------------+------- 1 | (0,2) 2 | (0,3) (2 rows) 

Deux tuples restent dans le tableau: VACUUM a décidé que le (0,2) tuple ne peut pas encore être aspiré. La raison en est certainement dans l'horizon des transactions de la base de données, qui dans cet exemple est déterminé par la transaction non terminée:

 | => SELECT backend_xmin FROM pg_stat_activity WHERE pid = pg_backend_pid(); 
 | backend_xmin | -------------- | 4006 | (1 row) 

Nous pouvons demander à VACUUM de signaler ce qui se passe:

 => VACUUM VERBOSE vac; 
 INFO: vacuuming "public.vac" INFO: index "vac_s" now contains 2 row versions in 2 pages DETAIL: 0 index row versions were removed. 0 index pages have been deleted, 0 are currently reusable. CPU: user: 0.00 s, system: 0.00 s, elapsed: 0.00 s. INFO: "vac": found 0 removable, 2 nonremovable row versions in 1 out of 1 pages DETAIL: 1 dead row versions cannot be removed yet, oldest xmin: 4006 There were 1 unused item pointers. Skipped 0 pages due to buffer pins, 0 frozen pages. 0 pages are entirely empty. CPU: user: 0.00 s, system: 0.00 s, elapsed: 0.00 s. VACUUM 

Notez que:

  • 2 nonremovable row versions - deux tuples qui ne peuvent pas être supprimés se trouvent dans le tableau.
  • 1 dead row versions cannot be removed yet - l'une d'elles est morte.
  • oldest xmin montre l'horizon actuel.

Reprenons la conclusion: si une base de données contient des transactions de longue durée (non terminées ou exécutées très longtemps), cela peut entraîner un ballonnement de la table, quelle que soit la fréquence de la mise sous vide. Par conséquent, les charges de travail de type OLTP et OLAP coexistent mal dans une seule base de données PostgreSQL: les rapports qui s'exécutent pendant des heures ne laisseront pas les tables mises à jour à vide. La création d'une réplique distincte à des fins de génération de rapports peut être une solution possible à ce problème.

Après l'achèvement d'une transaction ouverte, l'horizon se déplace et la situation se corrige:

 | => COMMIT; 

 => VACUUM VERBOSE vac; 
 INFO: vacuuming "public.vac" INFO: scanned index "vac_s" to remove 1 row versions DETAIL: CPU: user: 0.00 s, system: 0.00 s, elapsed: 0.00 s INFO: "vac": removed 1 row versions in 1 pages DETAIL: CPU: user: 0.00 s, system: 0.00 s, elapsed: 0.00 s INFO: index "vac_s" now contains 1 row versions in 2 pages DETAIL: 1 index row versions were removed. 0 index pages have been deleted, 0 are currently reusable. CPU: user: 0.00 s, system: 0.00 s, elapsed: 0.00 s. INFO: "vac": found 1 removable, 1 nonremovable row versions in 1 out of 1 pages DETAIL: 0 dead row versions cannot be removed yet, oldest xmin: 4008 There were 1 unused item pointers. Skipped 0 pages due to buffer pins, 0 frozen pages. 0 pages are entirely empty. CPU: user: 0.00 s, system: 0.00 s, elapsed: 0.00 s. VACUUM 

Désormais, seule la dernière version en direct de la ligne reste dans la page:

 => SELECT * FROM heap_page('vac',0); 
  ctid | state | xmin | xmax | hhu | hot | t_ctid -------+--------+----------+-------+-----+-----+-------- (0,1) | unused | | | | | (0,2) | unused | | | | | (0,3) | normal | 4007 (c) | 0 (a) | | | (0,3) (3 rows) 

L'index n'a également qu'une seule ligne:

 => SELECT * FROM index_page('vac_s',1); 
  itemoffset | ctid ------------+------- 1 | (0,3) (1 row) 

Que se passe-t-il à l'intérieur?


L'aspiration doit traiter la table et les index en même temps et le faire pour ne pas verrouiller les autres processus. Comment peut-il le faire?

Tout commence par la phase d' analyse du tas (la carte de visibilité prise en compte, comme déjà mentionné). Dans les pages lues, des tuples morts sont détectés et leurs tid sont enregistrés dans un tableau spécialisé. Le tableau est stocké dans la mémoire locale du processus de vide, où des octets de mémoire maintenance_work_mem lui sont alloués. La valeur par défaut de ce paramètre est 64 Mo. Notez que la quantité totale de mémoire est allouée à la fois, plutôt que lorsque le besoin s'en fait sentir. Cependant, si la table n'est pas grande, une quantité de mémoire plus petite est allouée.

Ensuite, nous atteignons la fin de la table ou la mémoire allouée au tableau est terminée. Dans les deux cas, la phase d' indexage sous vide démarre. À cette fin, chaque index créé sur la table est entièrement analysé à la recherche des lignes qui font référence aux tuples mémorisés. Les lignes trouvées sont aspirées loin des pages d'index.

Ici, nous sommes confrontés à ce qui suit: les index n'ont pas déjà de références à des tuples morts, tandis que la table les a toujours. Et cela n'est contraire à rien: lors de l'exécution d'une requête, nous ne frappons pas les tuples morts (avec accès à l'index) ou les rejetons lors du contrôle de visibilité (lors de l'analyse de la table).

Après cela, la phase de mise sous vide commence. Le tableau est à nouveau numérisé pour lire les pages appropriées, les aspirer des tuples mémorisés et libérer les pointeurs. Nous pouvons le faire car il n'y a plus de références à partir des index.

Si le tableau n'a pas été entièrement lu pendant le premier cycle, le tableau est effacé et tout est répété d'où nous sommes arrivés.

En résumé:

  • La table est toujours scannée deux fois.
  • Si la suppression de l'aspirateur supprime autant de tuples qu'ils ne tiennent pas tous dans la mémoire de taille maintenance_work_mem , tous les index seront analysés autant de fois que nécessaire.

Pour les grandes tables, cela peut prendre beaucoup de temps et ajouter une charge de travail système importante. Bien sûr, les requêtes ne seront pas verrouillées, mais des entrées / sorties supplémentaires sont définitivement indésirables.

Pour accélérer le processus, il est judicieux d'appeler VACUUM plus souvent (afin que trop peu de tuples soient aspirés à chaque fois) ou d'allouer plus de mémoire.

Pour noter entre parenthèses, à partir de la version 11, PostgreSQL peut ignorer les analyses d'index sauf si un besoin impérieux se présente. Cela doit faciliter la vie des propriétaires de grandes tables où les lignes sont uniquement ajoutées (mais pas modifiées).

Suivi


Comment pouvons-nous comprendre que VACUUM ne peut pas faire son travail en un seul cycle?

Nous avons déjà vu la première façon: d'appeler la commande VACUUM avec l'option VERBOSE. Dans ce cas, les informations sur les phases du processus seront transmises à la console.

Deuxièmement, à partir de la version 9.6, la vue pg_stat_progress_vacuum est disponible, qui fournit également toutes les informations nécessaires.

(La troisième méthode est également disponible: pour afficher les informations dans le journal des messages, mais cela ne fonctionne que pour le vide automatique, qui sera discuté la prochaine fois.)

Insérons un certain nombre de lignes dans le tableau, pour que le processus de vide dure assez longtemps, et mettons-les à jour pour que VACUUM puisse faire quelque chose.

 => TRUNCATE vac; => INSERT INTO vac(s) SELECT 'A' FROM generate_series(1,500000); => UPDATE vac SET s = 'B'; 

Réduisons la taille de la mémoire allouée au tableau d'identifiants:

 => ALTER SYSTEM SET maintenance_work_mem = '1MB'; => SELECT pg_reload_conf(); 

Commençons VACUUM et pendant qu'il fonctionne, pg_stat_progress_vacuum vue pg_stat_progress_vacuum plusieurs fois:

 => VACUUM VERBOSE vac; 

 | => SELECT * FROM pg_stat_progress_vacuum \gx 
 | -[ RECORD 1 ]------+------------------ | pid | 6715 | datid | 41493 | datname | test | relid | 57383 | phase | vacuuming indexes | heap_blks_total | 16667 | heap_blks_scanned | 2908 | heap_blks_vacuumed | 0 | index_vacuum_count | 0 | max_dead_tuples | 174762 | num_dead_tuples | 174480 

 | => SELECT * FROM pg_stat_progress_vacuum \gx 
 | -[ RECORD 1 ]------+------------------ | pid | 6715 | datid | 41493 | datname | test | relid | 57383 | phase | vacuuming indexes | heap_blks_total | 16667 | heap_blks_scanned | 5816 | heap_blks_vacuumed | 2907 | index_vacuum_count | 1 | max_dead_tuples | 174762 | num_dead_tuples | 174480 

Ici, nous pouvons voir, en particulier:

  • Le nom de la phase actuelle - nous avons discuté de trois phases principales, mais il y en a plus en général.
  • Nombre total de pages de table ( heap_blks_total ).
  • Nombre de pages numérisées ( heap_blks_scanned ).
  • Le nombre de pages déjà aspirées ( heap_blks_vacuumed ).
  • Le nombre de cycles de vide d'index ( index_vacuum_count ).

La progression générale est déterminée par le rapport de heap_blks_vacuumed à heap_blks_total , mais nous devons tenir compte du fait que cette valeur change par incréments importants plutôt qu'en douceur en raison de l'analyse des index. L'attention principale, cependant, doit être accordée au nombre de cycles de vide: un nombre supérieur à 1 signifie que la mémoire allouée n'était pas suffisante pour terminer l'aspiration en un cycle.

La sortie de la commande VACUUM VERBOSE, déjà terminée à ce moment, affichera l'image générale:

 INFO: vacuuming "public.vac" 
 INFO: scanned index "vac_s" to remove 174480 row versions DETAIL: CPU: user: 0.50 s, system: 0.07 s, elapsed: 1.36 s INFO: "vac": removed 174480 row versions in 2908 pages DETAIL: CPU: user: 0.02 s, system: 0.02 s, elapsed: 0.13 s 
 INFO: scanned index "vac_s" to remove 174480 row versions DETAIL: CPU: user: 0.26 s, system: 0.07 s, elapsed: 0.81 s INFO: "vac": removed 174480 row versions in 2908 pages DETAIL: CPU: user: 0.01 s, system: 0.02 s, elapsed: 0.10 s 
 INFO: scanned index "vac_s" to remove 151040 row versions DETAIL: CPU: user: 0.13 s, system: 0.04 s, elapsed: 0.47 s INFO: "vac": removed 151040 row versions in 2518 pages DETAIL: CPU: user: 0.01 s, system: 0.02 s, elapsed: 0.08 s 
 INFO: index "vac_s" now contains 500000 row versions in 17821 pages DETAIL: 500000 index row versions were removed. 8778 index pages have been deleted, 0 are currently reusable. CPU: user: 0.00 s, system: 0.00 s, elapsed: 0.00 s. INFO: "vac": found 500000 removable, 500000 nonremovable row versions in 16667 out of 16667 pages DETAIL: 0 dead row versions cannot be removed yet, oldest xmin: 4011 There were 0 unused item pointers. 0 pages are entirely empty. CPU: user: 1.10 s, system: 0.37 s, elapsed: 3.71 s. VACUUM 

Nous pouvons voir ici que trois cycles sur les index ont été effectués, et dans chaque cycle, 174480 pointeurs vers des tuples morts ont été aspirés. Pourquoi exactement ce nombre? Un tid occupe 6 octets et 1024 * 1024/6 = 174762, qui est le nombre que nous voyons dans pg_stat_progress_vacuum.max_dead_tuples . En réalité, un peu moins peut être utilisé: cela garantit que lors de la lecture d'une page suivante, tous les pointeurs vers des tuples morts resteront bien en mémoire.

Analyse


L'analyse, ou, en d'autres termes, la collecte de statistiques pour le planificateur de requêtes, n'a aucun lien formel avec le nettoyage. Néanmoins, nous pouvons effectuer l'analyse non seulement à l'aide de la commande ANALYSER, mais combiner l'aspiration et l'analyse dans VACUUM ANALYZE. Ici, le vide est fait d'abord, puis l'analyse, donc cela ne donne aucun gain.

Mais comme nous le verrons plus loin, le vide automatique et l'analyse automatique sont effectués en un seul processus et sont contrôlés de manière similaire.

ASPIRATEUR COMPLET


Comme indiqué ci-dessus, le vide libère plus d'espace que le vide sur la page, mais il ne résout toujours pas entièrement le problème.

Si pour certaines raisons la taille d'une table ou d'un index a beaucoup augmenté, VACUUM libérera de l'espace à l'intérieur des pages existantes: des "trous" y apparaîtront, qui seront ensuite utilisés pour l'insertion de nouveaux tuples. Mais le nombre de pages ne changera pas, et donc, du point de vue du système d'exploitation, les fichiers occuperont exactement le même espace qu'avant le vide. Et ce n'est pas bon car:

  • L'analyse complète de la table (ou de l'index) ralentit.
  • Un cache tampon plus important peut être nécessaire (car ce sont les pages qui y sont stockées et la densité des informations utiles diminue).
  • Dans l'arborescence d'index, un niveau supplémentaire peut se produire, ce qui ralentira l'accès à l'index.
  • Les fichiers occupent un espace supplémentaire sur le disque et dans les copies de sauvegarde.

(La seule exception concerne les pages entièrement aspirées, situées à la fin du fichier. Ces pages sont supprimées du fichier et retournées au système d'exploitation.)

Si la part des informations utiles dans les fichiers tombe en dessous d'une limite raisonnable, l'administrateur peut faire VACUUM FULL de la table. Dans ce cas, la table et tous ses index sont reconstruits à partir de zéro et les données sont compressées de manière généralement compacte (bien sûr, le paramètre fillfactor est pris en compte). Lors de la reconstruction, PostgreSQL reconstruit d'abord la table, puis chacun de ses index un par un. Pour chaque objet, de nouveaux fichiers sont créés et les anciens fichiers sont supprimés à la fin de la reconstruction. Nous devons tenir compte du fait que de l'espace disque supplémentaire sera nécessaire dans le processus.

Pour illustrer cela, insérons à nouveau un certain nombre de lignes dans le tableau:

 => TRUNCATE vac; => INSERT INTO vac(s) SELECT 'A' FROM generate_series(1,500000); 

Comment estimer la densité de l'information? Pour ce faire, il est pratique d'utiliser une extension spécialisée:

 => CREATE EXTENSION pgstattuple; => SELECT * FROM pgstattuple('vac') \gx 
 -[ RECORD 1 ]------+--------- table_len | 68272128 tuple_count | 500000 tuple_len | 64500000 tuple_percent | 94.47 dead_tuple_count | 0 dead_tuple_len | 0 dead_tuple_percent | 0 free_space | 38776 free_percent | 0.06 

La fonction lit l'ensemble du tableau et affiche des statistiques: quelles données occupent la place dans les fichiers. La principale information qui nous intéresse maintenant est le champ tuple_percent : le pourcentage de données utiles. Il est inférieur à 100 en raison de l'inévitable surcharge d'informations à l'intérieur d'une page, mais reste assez élevé.

Pour l'index, des informations différentes sont sorties, mais le champ avg_leaf_density a la même signification: le pourcentage d'informations utiles (dans les pages feuilles).

 => SELECT * FROM pgstatindex('vac_s') \gx 
 -[ RECORD 1 ]------+--------- version | 3 tree_level | 3 index_size | 72802304 root_block_no | 2722 internal_pages | 241 leaf_pages | 8645 empty_pages | 0 deleted_pages | 0 avg_leaf_density | 83.77 leaf_fragmentation | 64.25 

Et ce sont les tailles de la table et des index:

 => SELECT pg_size_pretty(pg_table_size('vac')) table_size, pg_size_pretty(pg_indexes_size('vac')) index_size; 
  table_size | index_size ------------+------------ 65 MB | 69 MB (1 row) 

Supprimons maintenant 90% de toutes les lignes. Nous faisons un choix aléatoire de lignes à supprimer, de sorte qu'au moins une ligne est très susceptible de rester dans chaque page:

 => DELETE FROM vac WHERE random() < 0.9; 
 DELETE 450189 

Quelle taille auront les objets après VIDE?

 => VACUUM vac; => SELECT pg_size_pretty(pg_table_size('vac')) table_size, pg_size_pretty(pg_indexes_size('vac')) index_size; 
  table_size | index_size ------------+------------ 65 MB | 69 MB (1 row) 

Nous pouvons voir que la taille n'a pas changé: VACUUM ne peut en aucun cas réduire la taille des fichiers. Et ce, bien que la densité de l'information ait diminué d'environ 10 fois:

 => SELECT vac.tuple_percent, vac_s.avg_leaf_density FROM pgstattuple('vac') vac, pgstatindex('vac_s') vac_s; 
  tuple_percent | avg_leaf_density ---------------+------------------ 9.41 | 9.73 (1 row) 

Maintenant, vérifions ce que nous obtenons après VACUUM FULL. Maintenant, la table et les index utilisent les fichiers suivants:

 => SELECT pg_relation_filepath('vac'), pg_relation_filepath('vac_s'); 
  pg_relation_filepath | pg_relation_filepath ----------------------+---------------------- base/41493/57392 | base/41493/57393 (1 row) 

 => VACUUM FULL vac; => SELECT pg_relation_filepath('vac'), pg_relation_filepath('vac_s'); 
  pg_relation_filepath | pg_relation_filepath ----------------------+---------------------- base/41493/57404 | base/41493/57407 (1 row) 

Les fichiers sont remplacés par de nouveaux maintenant. Les tailles du tableau et des index ont considérablement diminué, tandis que la densité de l'information a augmenté en conséquence:

 => SELECT pg_size_pretty(pg_table_size('vac')) table_size, pg_size_pretty(pg_indexes_size('vac')) index_size; 
  table_size | index_size ------------+------------ 6648 kB | 6480 kB (1 row) 
 => SELECT vac.tuple_percent, vac_s.avg_leaf_density FROM pgstattuple('vac') vac, pgstatindex('vac_s') vac_s; 
  tuple_percent | avg_leaf_density ---------------+------------------ 94.39 | 91.08 (1 row) 

Notez que la densité de l'information dans l'index est encore plus grande que celle d'origine. Il est plus avantageux de reconstruire un index (arbre B) à partir des données disponibles que d'insérer les données dans un index existant ligne par ligne.

Les fonctions de l'extension pgstattuple que nous avons utilisées lisent l'intégralité du tableau. Mais cela n'est pas pratique si le tableau est grand, donc l'extension a la fonction pgstattuple_approx , qui saute les pages marquées dans la carte de visibilité et affiche des chiffres approximatifs.

Une autre façon, mais encore moins précise, consiste à utiliser le catalogue système pour estimer approximativement le rapport entre la taille des données et la taille du fichier. Vous pouvez trouver des exemples de telles requêtes sur wiki .

VACUUM FULL n'est pas destiné à un usage régulier car il bloque tout travail avec la table (interrogation incluse) pendant toute la durée du processus. Il est clair que pour un système très utilisé, cela peut sembler inacceptable. Les verrous seront discutés séparément, et maintenant nous ne mentionnerons que l'extension pg_repack , qui ne verrouille la table que pendant une courte période à la fin du travail.

Commandes similaires


Il existe quelques commandes qui reconstruisent également entièrement les tables et les index et ressemblent donc à VACUUM FULL. Tous bloquent complètement tout travail avec la table, ils suppriment tous les anciens fichiers de données et en créent de nouveaux.

La commande CLUSTER est globalement similaire à VACUUM FULL, mais elle ordonne également physiquement les tuples selon l'un des index disponibles. Cela permet au planificateur d'utiliser l'accès à l'index plus efficacement dans certains cas. Mais nous devons garder à l'esprit que le clustering n'est pas maintenu: l'ordre physique des tuples sera rompu avec les modifications ultérieures de la table.

La commande REINDEX reconstruit un index distinct sur la table. VACUUM FULL et CLUSTER utilisent réellement cette commande pour reconstruire les index.

La logique de la commande TRUNCATE est similaire à celle de DELETE - elle supprime toutes les lignes de table. Mais DELETE, comme cela a déjà été mentionné, ne marque que les tuples comme supprimés, ce qui nécessite un nettoyage supplémentaire. Et TRUNCATE crée simplement un nouveau fichier propre à la place. En règle générale, cela fonctionne plus rapidement, mais nous devons garder à l'esprit que TRUNCATE bloquera tout travail avec la table jusqu'à la fin de la transaction.

Continuez à lire .

Source: https://habr.com/ru/post/fr484106/


All Articles