[Trad] [svn:pgfr] r1355 - in traduc/tags: . tv840rc2
admin at listes.postgresql.fr
admin at listes.postgresql.fr
Sam 27 Juin 12:41:55 CEST 2009
Author: gleu
Date: 2009-06-27 12:41:54 +0200 (Sat, 27 Jun 2009)
New Revision: 1355
Added:
traduc/tags/tv840rc2/
traduc/tags/tv840rc2/gist.xml
traduc/tags/tv840rc2/storage.xml
Removed:
traduc/tags/tv840rc2/gist.xml
traduc/tags/tv840rc2/storage.xml
Log:
Ajout du tag de la 8.4 RC2.
Property changes on: traduc/tags/tv840rc2
___________________________________________________________________
Added: svn:mergeinfo
+
Deleted: traduc/tags/tv840rc2/gist.xml
===================================================================
--- traduc/trunk/postgresql/gist.xml 2009-06-23 22:14:31 UTC (rev 1352)
+++ traduc/tags/tv840rc2/gist.xml 2009-06-27 10:41:54 UTC (rev 1355)
@@ -1,687 +0,0 @@
-<?xml version="1.0" encoding="ISO-8859-15"?>
-<!-- Dernière modification
- le $Date$
- par $Author$
- révision $Revision$ -->
-
-<chapter id="gist">
-<title>Index GiST</title>
-
- <indexterm>
- <primary>index</primary>
- <secondary>GiST</secondary>
- </indexterm>
-
-<sect1 id="gist-intro">
- <title>Introduction</title>
-
- <para>
- <acronym>GiST</acronym> est un acronyme de <foreignphrase>Generalized
- Search Tree</foreignphrase>, c'est-à-dire arbre de recherche généralisé.
- C'est une méthode d'accès balancée à structure de type arbre,
- qui agit comme un modèle de base dans lequel il est possible d'implanter
- des schémas d'indexage arbitraires. B-trees, R-trees et de nombreux autres
- schémas d'indexage peuvent être implantés en <acronym>GiST</acronym>.
- </para>
-
- <para>
- <acronym>GiST</acronym> a pour avantage d'autoriser le développement
- de types de données personnalisés avec les méthodes d'accès appropriées, par
- un expert en types de données, plutôt que par un expert en
- bases de données.
- </para>
-
- <para>
- Quelques informations disponibles ici sont dérivées du <ulink
- url="http://gist.cs.berkeley.edu/">site web</ulink> du projet d'indexage
- GiST de l'université de Californie à Berkeley et de la <ulink
- url="http://www.sai.msu.su/~megera/postgres/gist/papers/concurrency/access-methods-for-next-generation.pdf.gz">thèse
- de Marcel Kornacker,
- Méthodes d'accès pour les systèmes de bases de données de la prochaine
- génération</ulink>. L'implantation <acronym>GiST</acronym> de
- <productname>PostgreSQL</productname> est principalement maintenu
- par Teodor Sigaev et Oleg Bartunov. Leur <ulink
- url="http://www.sai.msu.su/~megera/postgres/gist/">site web</ulink> fournit
- de plus amples informations.
- </para>
-
-</sect1>
-
-<sect1 id="gist-extensibility">
- <title>Extensibilité</title>
-
- <para>
- L'implantation d'une nouvelle méthode d'accès à un index
- a toujours été un travail complexe. Il est, en effet, nécessaire de comprendre le
- fonctionnement interne de la base de données, tel que le gestionnaire de
- verrous ou le WAL.
- </para>
- <para>
- L'interface <acronym>GiST</acronym> dispose d'un haut niveau
- d'abstraction, ce qui autorise le codeur de la méthode d'accès à
- ne coder que la sémantique du type de données accédé. La
- couche <acronym>GiST</acronym> se charge elle-même de la gestion des accès concurrents,
- des traces et de la recherche dans la structure en arbre.
- </para>
-
- <para>
- Cette extensibilité n'est pas comparable à celle des
- autres arbres de recherche standard en termes de données gérées. Par
- exemple, <productname>PostgreSQL</productname> supporte les B-trees et les
- index de hachage extensibles. Cela signifie qu'il est possible d'utiliser
- <productname>PostgreSQL</productname> pour construire un B-tree ou un hachage
- sur tout type de données. Mais, les B-trees ne supportent
- que les prédicats d'échelle (<literal><</literal>,
- <literal>=</literal>, <literal>></literal>), les index de hachage
- que les requêtes d'égalité.
- </para>
-
- <para>
- Donc, lors de l'indexation d'une collection d'images, par exemple, avec un B-tree
- <productname>PostgreSQL</productname>, seules peuvent être lancées des requêtes de type
- <quote>est-ce que imagex est égale à imagey</quote>,
- <quote>est-ce que imagex est plus petite que imagey</quote> et <quote>est-ce
- que imagex est plus grande que imagey</quote>. En fonction de la définition
- donnée à <quote>égale à</quote>, <quote>inférieure à</quote> ou
- <quote>supérieure à</quote>, cela peut avoir une utilité.
- Néanmoins, l'utilisation d'un index basé sur <acronym>GiST</acronym> permet
- de créer de nombreuses possibilités de poser des questions spécifiques au domaine,
- telles que <quote>trouver toutes les images de chevaux</quote> ou
- <quote>trouver toutes les images sur-exposées</quote>.
- </para>
-
- <para>
- Pour obtenir une méthode d'accès
- <acronym>GiST</acronym> fonctionnelle, il suffit de coder sept méthodes
- utilisateur définissant le comportement des clés dans
- l'arbre. Ces méthodes doivent être suffisamment élaborées
- pour supporter des requêtes avancées, mais pour toutes les requêtes standard
- (B-trees, R-trees, etc.) elles sont relativement simples. En bref,
- <acronym>GiST</acronym> combine extensibilité, généralité,
- ré-utilisation de code et interface claire.
- </para>
-
-</sect1>
-
-<sect1 id="gist-implementation">
- <title>Implantation</title>
-
- <para>
- Une classe d'opérateur d'index <acronym>GiST</acronym> doit fournir sept
- méthodes. Correctness of the index is ensured
- by proper implementation of the <function>same</function>, <function>consistent</function>
- and <function>union</function> methods, while efficiency (size and speed) of the
- index will depend on the <function>penalty</function> and <function>picksplit</function>
- methods.
- The remaining two methods are <function>compress</function> and
- <function>decompress</function>, which allow an index to have internal tree data of
- a different type than the data it indexes. The leaves are to be of the
- indexed data type, while the other tree nodes can be of any C struct (but
- you still have to follow <productname>PostgreSQL</productname> datatype rules here,
- see about <literal>varlena</literal> for variable sized data). If the tree's
- internal data type exists at the SQL level, the <literal>STORAGE</literal> option
- of the <command>CREATE OPERATOR CLASS</command> command can be used.
-
- </para>
-
- <variablelist>
- <varlistentry>
- <term><function>consistent</function></term>
- <listitem>
- <para>
- Given an index entry <literal>p</literal> and a query value <literal>q</literal>,
- this function determines whether the index entry is
- <quote>consistent</quote> with the query; that is, could the predicate
- <quote><replaceable>indexed_column</replaceable>
- <replaceable>indexable_operator</replaceable> <literal>q</literal></quote> be true for
- any row represented by the index entry? For a leaf index entry this is
- equivalent to testing the indexable condition, while for an internal
- tree node this determines whether it is necessary to scan the subtree
- of the index represented by the tree node. When the result is
- <literal>true</literal>, a <literal>recheck</literal> flag must also be returned.
- This indicates whether the predicate is certainly true or only possibly
- true. If <literal>recheck</literal> = <literal>false</literal> then the index has
- tested the predicate condition exactly, whereas if <literal>recheck</literal>
- = <literal>true</literal> the row is only a candidate match. In that case the
- system will automatically evaluate the
- <replaceable>indexable_operator</replaceable> against the actual row value to see
- if it is really a match. This convention allows
- <acronym>GiST</acronym> to support both lossless and lossy index
- structures.
- </para>
-
- <para>
- The <acronym>SQL</acronym> declaration of the function must look like this:
-
-<programlisting>
-CREATE OR REPLACE FUNCTION my_consistent(internal, data_type, smallint, oid, internal)
-RETURNS bool
-AS 'MODULE_PATHNAME'
-LANGUAGE C STRICT;
-</programlisting>
-
- And the matching code in the C module could then follow this skeleton:
-
-<programlisting>
-Datum my_consistent(PG_FUNCTION_ARGS);
-PG_FUNCTION_INFO_V1(my_consistent);
-
-Datum
-my_consistent(PG_FUNCTION_ARGS)
-{
- GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
- data_type *query = PG_GETARG_DATA_TYPE_P(1);
- StrategyNumber strategy = (StrategyNumber) PG_GETARG_UINT16(2);
- /* Oid subtype = PG_GETARG_OID(3); */
- bool *recheck = (bool *) PG_GETARG_POINTER(4);
- data_type *key = DatumGetDataType(entry->key);
- bool retval;
-
- /*
- * determine return value as a function of strategy, key and query.
- *
- * Use GIST_LEAF(entry) to know where you're called in the index tree,
- * which comes handy when supporting the = operator for example (you could
- * check for non empty union() in non-leaf nodes and equality in leaf
- * nodes).
- */
-
- *recheck = true; /* or false if check is exact */
-
- PG_RETURN_BOOL(retval);
-}
-</programlisting>
-
- Here, <varname>key</varname> is an element in the index and <varname>query</varname>
- the value being looked up in the index. The <literal>StrategyNumber</literal>
- parameter indicates which operator of your operator class is being
- applied — it matches one of the operator numbers in the
- <command>CREATE OPERATOR CLASS</command> command. Depending on what operators
- you have included in the class, the data type of <varname>query</varname> could
- vary with the operator, but the above skeleton assumes it doesn't.
- </para>
-
- </listitem>
- </varlistentry>
-
- <varlistentry>
- <term><function>union</function></term>
- <listitem>
- <para>
- This method consolidates information in the tree. Given a set of
- entries, this function generates a new index entry that represents
- all the given entries.
- </para>
-
- <para>
- The <acronym>SQL</acronym> declaration of the function must look like this:
-
-<programlisting>
-CREATE OR REPLACE FUNCTION my_union(internal, internal)
-RETURNS internal
-AS 'MODULE_PATHNAME'
-LANGUAGE C STRICT;
-</programlisting>
-
- And the matching code in the C module could then follow this skeleton:
-
-<programlisting>
-Datum my_union(PG_FUNCTION_ARGS);
-PG_FUNCTION_INFO_V1(my_union);
-
-Datum
-my_union(PG_FUNCTION_ARGS)
-{
- GistEntryVector *entryvec = (GistEntryVector *) PG_GETARG_POINTER(0);
- GISTENTRY *ent = entryvec->vector;
- data_type *out,
- *tmp,
- *old;
- int numranges,
- i = 0;
-
- numranges = entryvec->n;
- tmp = DatumGetDataType(ent[0].key);
- out = tmp;
-
- if (numranges == 1)
- {
- out = data_type_deep_copy(tmp);
-
- PG_RETURN_DATA_TYPE_P(out);
- }
-
- for (i = 1; i < numranges; i++)
- {
- old = out;
- tmp = DatumGetDataType(ent[i].key);
- out = my_union_implementation(out, tmp);
- }
-
- PG_RETURN_DATA_TYPE_P(out);
-}
-</programlisting>
- </para>
-
- <para>
- As you can see, in this skeleton we're dealing with a data type
- where <literal>union(X, Y, Z) = union(union(X, Y), Z)</literal>. It's easy
- enough to support data types where this is not the case, by
- implementing the proper union algorithm in this
- <acronym>GiST</acronym> support method.
- </para>
-
- <para>
- The <function>union</function> implementation function should return a
- pointer to newly <function>palloc()</function>ed memory. You can't just
- return whatever the input is.
- </para>
- </listitem>
- </varlistentry>
-
- <varlistentry>
- <term><function>compress</function></term>
- <listitem>
- <para>
- Convertit l'élément de données dans un format compatible avec
- le stockage physique dans une page d'index.
- </para>
-
- <para>
- The <acronym>SQL</acronym> declaration of the function must look like this:
-
-<programlisting>
-CREATE OR REPLACE FUNCTION my_compress(internal)
-RETURNS internal
-AS 'MODULE_PATHNAME'
-LANGUAGE C STRICT;
-</programlisting>
-
- And the matching code in the C module could then follow this skeleton:
-
-<programlisting>
-Datum my_compress(PG_FUNCTION_ARGS);
-PG_FUNCTION_INFO_V1(my_compress);
-
-Datum
-my_compress(PG_FUNCTION_ARGS)
-{
- GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
- GISTENTRY *retval;
-
- if (entry->leafkey)
- {
- /* replace entry->key with a compressed version */
- compressed_data_type *compressed_data = palloc(sizeof(compressed_data_type));
-
- /* fill *compressed_data from entry->key ... */
-
- retval = palloc(sizeof(GISTENTRY));
- gistentryinit(*retval, PointerGetDatum(compressed_data),
- entry->rel, entry->page, entry->offset, FALSE);
- }
- else
- {
- /* typically we needn't do anything with non-leaf entries */
- retval = entry;
- }
-
- PG_RETURN_POINTER(retval);
-}
-</programlisting>
- </para>
-
- <para>
- You have to adapt <replaceable>compressed_data_type</replaceable> to the specific
- type you're converting to in order to compress your leaf nodes, of
- course.
- </para>
-
- <para>
- Depending on your needs, you could also need to care about
- compressing <literal>NULL</literal> values in there, storing for example
- <literal>(Datum) 0</literal> like <literal>gist_circle_compress</literal> does.
- </para>
- </listitem>
- </varlistentry>
-
- <varlistentry>
- <term><function>decompress</function></term>
- <listitem>
- <para>
- L'inverse de la fonction <function>compress</function>. Convertit la
- représentation de l'élément de donnée en un format manipulable par la base
- de données.
- </para>
-
- <para>
- The <acronym>SQL</acronym> declaration of the function must look like this:
-
-<programlisting>
-CREATE OR REPLACE FUNCTION my_decompress(internal)
-RETURNS internal
-AS 'MODULE_PATHNAME'
-LANGUAGE C STRICT;
-</programlisting>
-
- And the matching code in the C module could then follow this skeleton:
-
-<programlisting>
-Datum my_decompress(PG_FUNCTION_ARGS);
-PG_FUNCTION_INFO_V1(my_decompress);
-
-Datum
-my_decompress(PG_FUNCTION_ARGS)
-{
- PG_RETURN_POINTER(PG_GETARG_POINTER(0));
-}
-</programlisting>
-
- The above skeleton is suitable for the case where no decompression
- is needed.
- </para>
- </listitem>
- </varlistentry>
-
- <varlistentry>
- <term><function>penalty</function></term>
- <listitem>
- <para>
- Renvoie une valeur indiquant le <quote>coût</quote> d'insertion
- d'une nouvelle entrée dans une branche particulière de l'arbre. Les
- éléments seront insérés dans l'ordre des pénalités moindres
- (<function>penalty</function>) de l'arbre.
- </para>
-
- <para>
- The <acronym>SQL</acronym> declaration of the function must look like this:
-
-<programlisting>
-CREATE OR REPLACE FUNCTION my_penalty(internal, internal, internal)
-RETURNS internal
-AS 'MODULE_PATHNAME'
-LANGUAGE C STRICT; -- in some cases penalty functions need not be strict
-</programlisting>
-
- And the matching code in the C module could then follow this skeleton:
-
-<programlisting>
-Datum my_penalty(PG_FUNCTION_ARGS);
-PG_FUNCTION_INFO_V1(my_penalty);
-
-Datum
-my_penalty(PG_FUNCTION_ARGS)
-{
- GISTENTRY *origentry = (GISTENTRY *) PG_GETARG_POINTER(0);
- GISTENTRY *newentry = (GISTENTRY *) PG_GETARG_POINTER(1);
- float *penalty = (float *) PG_GETARG_POINTER(2);
- data_type *orig = DatumGetDataType(origentry->key);
- data_type *new = DatumGetDataType(newentry->key);
-
- *penalty = my_penalty_implementation(orig, new);
- PG_RETURN_POINTER(penalty);
-}
-</programlisting>
- </para>
-
- <para>
- The <function>penalty</function> function is crucial to good performance of
- the index. It'll get used at insertion time to determine which branch
- to follow when choosing where to add the new entry in the tree. At
- query time, the more balanced the index, the quicker the lookup.
- </para>
- </listitem>
- </varlistentry>
-
- <varlistentry>
- <term><function>picksplit</function></term>
- <listitem>
- <para>
- When an index page split is necessary, this function decides which
- entries on the page are to stay on the old page, and which are to move
- to the new page.
- </para>
-
- <para>
- The <acronym>SQL</acronym> declaration of the function must look like this:
-
-<programlisting>
-CREATE OR REPLACE FUNCTION my_picksplit(internal, internal)
-RETURNS internal
-AS 'MODULE_PATHNAME'
-LANGUAGE C STRICT;
-</programlisting>
-
- And the matching code in the C module could then follow this skeleton:
-
-<programlisting>
-Datum my_picksplit(PG_FUNCTION_ARGS);
-PG_FUNCTION_INFO_V1(my_picksplit);
-
-Datum
-my_picksplit(PG_FUNCTION_ARGS)
-{
- GistEntryVector *entryvec = (GistEntryVector *) PG_GETARG_POINTER(0);
- OffsetNumber maxoff = entryvec->n - 1;
- GISTENTRY *ent = entryvec->vector;
- GIST_SPLITVEC *v = (GIST_SPLITVEC *) PG_GETARG_POINTER(1);
- int i,
- nbytes;
- OffsetNumber *left,
- *right;
- data_type *tmp_union;
- data_type *unionL;
- data_type *unionR;
- GISTENTRY **raw_entryvec;
-
- maxoff = entryvec->n - 1;
- nbytes = (maxoff + 1) * sizeof(OffsetNumber);
-
- v->spl_left = (OffsetNumber *) palloc(nbytes);
- left = v->spl_left;
- v->spl_nleft = 0;
-
- v->spl_right = (OffsetNumber *) palloc(nbytes);
- right = v->spl_right;
- v->spl_nright = 0;
-
- unionL = NULL;
- unionR = NULL;
-
- /* Initialize the raw entry vector. */
- raw_entryvec = (GISTENTRY **) malloc(entryvec->n * sizeof(void *));
- for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i))
- raw_entryvec[i] = &(entryvec->vector[i]);
-
- for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i))
- {
- int real_index = raw_entryvec[i] - entryvec->vector;
-
- tmp_union = DatumGetDataType(entryvec->vector[real_index].key);
- Assert(tmp_union != NULL);
-
- /*
- * Choose where to put the index entries and update unionL and unionR
- * accordingly. Append the entries to either v_spl_left or
- * v_spl_right, and care about the counters.
- */
-
- if (my_choice_is_left(unionL, curl, unionR, curr))
- {
- if (unionL == NULL)
- unionL = tmp_union;
- else
- unionL = my_union_implementation(unionL, tmp_union);
-
- *left = real_index;
- ++left;
- ++(v->spl_nleft);
- }
- else
- {
- /*
- * Same on the right
- */
- }
- }
-
- v->spl_ldatum = DataTypeGetDatum(unionL);
- v->spl_rdatum = DataTypeGetDatum(unionR);
- PG_RETURN_POINTER(v);
-}
-</programlisting>
- </para>
-
- <para>
- Like <function>penalty</function>, the <function>picksplit</function> function
- is crucial to good performance of the index. Designing suitable
- <function>penalty</function> and <function>picksplit</function> implementations
- is where the challenge of implementing well-performing
- <acronym>GiST</acronym> indexes lies.
- </para>
- </listitem>
- </varlistentry>
-
- <varlistentry>
- <term><function>same</function></term>
- <listitem>
- <para>
- Returns true if two index entries are identical, false otherwise.
- </para>
-
- <para>
- The <acronym>SQL</acronym> declaration of the function must look like this:
-
-<programlisting>
-CREATE OR REPLACE FUNCTION my_same(internal, internal, internal)
-RETURNS internal
-AS 'MODULE_PATHNAME'
-LANGUAGE C STRICT;
-</programlisting>
-
- And the matching code in the C module could then follow this skeleton:
-
-<programlisting>
-Datum my_same(PG_FUNCTION_ARGS);
-PG_FUNCTION_INFO_V1(my_same);
-
-Datum
-my_same(PG_FUNCTION_ARGS)
-{
- prefix_range *v1 = PG_GETARG_PREFIX_RANGE_P(0);
- prefix_range *v2 = PG_GETARG_PREFIX_RANGE_P(1);
- bool *result = (bool *) PG_GETARG_POINTER(2);
-
- *result = my_eq(v1, v2);
- PG_RETURN_POINTER(result);
-}
-</programlisting>
-
- For historical reasons, the <function>same</function> function doesn't
- just return a boolean result; instead it has to store the flag
- at the location indicated by the third argument.
- </para>
- </listitem>
- </varlistentry>
-
- </variablelist>
-
-</sect1>
-
-<sect1 id="gist-examples">
- <title>Exemples</title>
-
- <para>
- La distribution source de <productname>PostgreSQL</productname> inclut
- plusieurs exemples de méthodes d'indexation implantées selon
- <acronym>GiST</acronym>. Le système principal fournit des fonctionnalités
- de recherche plein texte (indexation des <type>tsvector</type> et
- <type>tsquery</type>) ainsi que des fonctionnalités équivalentes aux R-Tree
- pour certains types de données géométriques
- (voir <filename>src/backend/access/gist/gistproc.c</filename>). Les modules
- <filename>contrib</filename> suivants contiennent aussi des classes d'opérateur
- <acronym>GiST</acronym> :
- </para>
-
- <variablelist>
- <varlistentry>
- <term>btree_gist</term>
- <listitem>
- <para>Fonctionnalités équivalentes aux B-Tree pour plusieurs types de
- données</para>
- </listitem>
- </varlistentry>
-
- <varlistentry>
- <term>cube</term>
- <listitem>
- <para>Indexation de cubes multi-dimensionnels</para>
- </listitem>
- </varlistentry>
-
- <varlistentry>
- <term>hstore</term>
- <listitem>
- <para>Module pour le stockage des paires (clé, valeur)</para>
- </listitem>
- </varlistentry>
-
- <varlistentry>
- <term>intarray</term>
- <listitem>
- <para>RD-Tree pour tableaux uni-dimensionnels de valeurs int4</para>
- </listitem>
- </varlistentry>
-
- <varlistentry>
- <term>ltree</term>
- <listitem>
- <para>Indexation des structures de type arbre</para>
- </listitem>
- </varlistentry>
-
- <varlistentry>
- <term>pg_trgm</term>
- <listitem>
- <para>Similarité textuelle par correspondance de trigrammes</para>
- </listitem>
- </varlistentry>
-
- <varlistentry>
- <term>seg</term>
- <listitem>
- <para>Indexation pour les <quote>nombres
- flottants</quote></para>
- </listitem>
- </varlistentry>
- </variablelist>
-
-</sect1>
-
-<sect1 id="gist-recovery">
- <title>Récupération après un arrêt brutal</title>
-
- <para>
- Il est généralement suffisant de rejouer les traces WAL pour restaurer l'intégrité d'un
- index GiST après un arrêt brutal de la base de données. Néanmoins, il existe
- quelques cas particuliers pour lesquels l'état de l'index n'est pas
- entièrement reconstruit. L'index reste fonctionnellement correct mais
- les performances peuvent se trouver dégradées. Lorsque cela
- arrive, l'index peut être réparé par <command>VACUUM</command> de sa table, ou
- par reconstruction avec <command>REINDEX</command>. Dans certains cas, un simple
- <command>VACUUM</command> ne suffit pas et un <command>VACUUM FULL</command>
- ou un <command>REINDEX</command> est nécessaire. Ce besoin est indiqué par
- la survenue d'un tel message :
-<programlisting>LOG: index NNN/NNN/NNN needs VACUUM or REINDEX to finish crash recovery
-</programlisting>
- ou le message suivant lors d'insertions dans l'index :
-<programlisting>LOG: index "FOO" needs VACUUM or REINDEX to finish crash recovery
-</programlisting>
- Si un simple <command>VACUUM</command> est incapable de réaliser
- complètement la récupération, l'avertissement suivant est envoyé :
-<programlisting>NOTICE: index "FOO" needs VACUUM FULL or REINDEX to finish crash recovery
-</programlisting>
- </para>
-</sect1>
-
-</chapter>
Copied: traduc/tags/tv840rc2/gist.xml (from rev 1353, traduc/trunk/postgresql/gist.xml)
===================================================================
--- traduc/tags/tv840rc2/gist.xml (rev 0)
+++ traduc/tags/tv840rc2/gist.xml 2009-06-27 10:41:54 UTC (rev 1355)
@@ -0,0 +1,704 @@
+<?xml version="1.0" encoding="ISO-8859-15"?>
+<!-- Dernière modification
+ le $Date$
+ par $Author$
+ révision $Revision$ -->
+
+<chapter id="gist">
+<title>Index GiST</title>
+
+ <indexterm>
+ <primary>index</primary>
+ <secondary>GiST</secondary>
+ </indexterm>
+
+<sect1 id="gist-intro">
+ <title>Introduction</title>
+
+ <para>
+ <acronym>GiST</acronym> est un acronyme de <foreignphrase>Generalized
+ Search Tree</foreignphrase>, c'est-à-dire arbre de recherche généralisé.
+ C'est une méthode d'accès balancée à structure de type arbre,
+ qui agit comme un modèle de base dans lequel il est possible d'implanter
+ des schémas d'indexage arbitraires. B-trees, R-trees et de nombreux autres
+ schémas d'indexage peuvent être implantés en <acronym>GiST</acronym>.
+ </para>
+
+ <para>
+ <acronym>GiST</acronym> a pour avantage d'autoriser le développement
+ de types de données personnalisés avec les méthodes d'accès appropriées, par
+ un expert en types de données, plutôt que par un expert en
+ bases de données.
+ </para>
+
+ <para>
+ Quelques informations disponibles ici sont dérivées du <ulink
+ url="http://gist.cs.berkeley.edu/">site web</ulink> du projet d'indexage
+ GiST de l'université de Californie à Berkeley et de la <ulink
+ url="http://www.sai.msu.su/~megera/postgres/gist/papers/concurrency/access-methods-for-next-generation.pdf.gz">thèse
+ de Marcel Kornacker,
+ Méthodes d'accès pour les systèmes de bases de données de la prochaine
+ génération</ulink>. L'implantation <acronym>GiST</acronym> de
+ <productname>PostgreSQL</productname> est principalement maintenu
+ par Teodor Sigaev et Oleg Bartunov. Leur <ulink
+ url="http://www.sai.msu.su/~megera/postgres/gist/">site web</ulink> fournit
+ de plus amples informations.
+ </para>
+
+</sect1>
+
+<sect1 id="gist-extensibility">
+ <title>Extensibilité</title>
+
+ <para>
+ L'implantation d'une nouvelle méthode d'accès à un index
+ a toujours été un travail complexe. Il est, en effet, nécessaire de comprendre le
+ fonctionnement interne de la base de données, tel que le gestionnaire de
+ verrous ou le WAL.
+ </para>
+
+ <para>
+ L'interface <acronym>GiST</acronym> dispose d'un haut niveau
+ d'abstraction, ce qui autorise le codeur de la méthode d'accès à
+ ne coder que la sémantique du type de données accédé. La
+ couche <acronym>GiST</acronym> se charge elle-même de la gestion des accès concurrents,
+ des traces et de la recherche dans la structure en arbre.
+ </para>
+
+ <para>
+ Cette extensibilité n'est pas comparable à celle des
+ autres arbres de recherche standard en termes de données gérées. Par
+ exemple, <productname>PostgreSQL</productname> supporte les B-trees et les
+ index de hachage extensibles. Cela signifie qu'il est possible d'utiliser
+ <productname>PostgreSQL</productname> pour construire un B-tree ou un hachage
+ sur tout type de données. Mais, les B-trees ne supportent
+ que les prédicats d'échelle (<literal><</literal>,
+ <literal>=</literal>, <literal>></literal>), les index de hachage
+ que les requêtes d'égalité.
+ </para>
+
+ <para>
+ Donc, lors de l'indexation d'une collection d'images, par exemple, avec un B-tree
+ <productname>PostgreSQL</productname>, seules peuvent être lancées des requêtes de type
+ <quote>est-ce que imagex est égale à imagey</quote>,
+ <quote>est-ce que imagex est plus petite que imagey</quote> et <quote>est-ce
+ que imagex est plus grande que imagey</quote>. En fonction de la définition
+ donnée à <quote>égale à</quote>, <quote>inférieure à</quote> ou
+ <quote>supérieure à</quote>, cela peut avoir une utilité.
+ Néanmoins, l'utilisation d'un index basé sur <acronym>GiST</acronym> permet
+ de créer de nombreuses possibilités de poser des questions spécifiques au domaine,
+ telles que <quote>trouver toutes les images de chevaux</quote> ou
+ <quote>trouver toutes les images sur-exposées</quote>.
+ </para>
+
+ <para>
+ Pour obtenir une méthode d'accès
+ <acronym>GiST</acronym> fonctionnelle, il suffit de coder sept méthodes
+ utilisateur définissant le comportement des clés dans
+ l'arbre. Ces méthodes doivent être suffisamment élaborées
+ pour supporter des requêtes avancées, mais pour toutes les requêtes standard
+ (B-trees, R-trees, etc.) elles sont relativement simples. En bref,
+ <acronym>GiST</acronym> combine extensibilité, généralité,
+ ré-utilisation de code et interface claire.
+ </para>
+
+</sect1>
+
+<sect1 id="gist-implementation">
+ <title>Implantation</title>
+
+ <para>
+ Une classe d'opérateur d'index <acronym>GiST</acronym> doit fournir sept
+ méthodes. Correctness of the index is ensured
+ by proper implementation of the <function>same</function>, <function>consistent</function>
+ and <function>union</function> methods, while efficiency (size and speed) of the
+ index will depend on the <function>penalty</function> and <function>picksplit</function>
+ methods.
+ The remaining two methods are <function>compress</function> and
+ <function>decompress</function>, which allow an index to have internal tree data of
+ a different type than the data it indexes. The leaves are to be of the
+ indexed data type, while the other tree nodes can be of any C struct (but
+ you still have to follow <productname>PostgreSQL</productname> datatype rules here,
+ see about <literal>varlena</literal> for variable sized data). If the tree's
+ internal data type exists at the SQL level, the <literal>STORAGE</literal> option
+ of the <command>CREATE OPERATOR CLASS</command> command can be used.
+ </para>
+
+ <variablelist>
+ <varlistentry>
+ <term><function>consistent</function></term>
+ <listitem>
+ <para>
+ Given an index entry <literal>p</literal> and a query value <literal>q</literal>,
+ this function determines whether the index entry is
+ <quote>consistent</quote> with the query; that is, could the predicate
+ <quote><replaceable>indexed_column</replaceable>
+ <replaceable>indexable_operator</replaceable> <literal>q</literal></quote> be true for
+ any row represented by the index entry? For a leaf index entry this is
+ equivalent to testing the indexable condition, while for an internal
+ tree node this determines whether it is necessary to scan the subtree
+ of the index represented by the tree node. When the result is
+ <literal>true</literal>, a <literal>recheck</literal> flag must also be returned.
+ This indicates whether the predicate is certainly true or only possibly
+ true. If <literal>recheck</literal> = <literal>false</literal> then the index has
+ tested the predicate condition exactly, whereas if <literal>recheck</literal>
+ = <literal>true</literal> the row is only a candidate match. In that case the
+ system will automatically evaluate the
+ <replaceable>indexable_operator</replaceable> against the actual row value to see
+ if it is really a match. This convention allows
+ <acronym>GiST</acronym> to support both lossless and lossy index
+ structures.
+ </para>
+
+ <para>
+ La déclaration <acronym>SQL</acronym> de la fonction doit ressembler à
+ ceci :
+
+<programlisting>
+CREATE OR REPLACE FUNCTION my_consistent(internal, data_type, smallint, oid, internal)
+RETURNS bool
+AS 'MODULE_PATHNAME'
+LANGUAGE C STRICT;
+</programlisting>
+
+ Et le code correspondant dans le module C peut alors suivre ce
+ squelette :
+
+<programlisting>
+Datum my_consistent(PG_FUNCTION_ARGS);
+PG_FUNCTION_INFO_V1(my_consistent);
+
+Datum
+my_consistent(PG_FUNCTION_ARGS)
+{
+ GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
+ data_type *query = PG_GETARG_DATA_TYPE_P(1);
+ StrategyNumber strategy = (StrategyNumber) PG_GETARG_UINT16(2);
+ /* Oid subtype = PG_GETARG_OID(3); */
+ bool *recheck = (bool *) PG_GETARG_POINTER(4);
+ data_type *key = DatumGetDataType(entry->key);
+ bool retval;
+
+ /*
+ * determine return value as a function of strategy, key and query.
+ *
+ * Use GIST_LEAF(entry) to know where you're called in the index tree,
+ * which comes handy when supporting the = operator for example (you could
+ * check for non empty union() in non-leaf nodes and equality in leaf
+ * nodes).
+ */
+
+ *recheck = true; /* or false if check is exact */
+
+ PG_RETURN_BOOL(retval);
+}
+</programlisting>
+
+ Ici, <varname>key</varname> est un élément dans l'index et
+ <varname>query</varname> la valeur la recherchée dans l'index. Le
+ paramètre <literal>StrategyNumber</literal> indique l'opérateur
+ appliqué de votre classe d'opérateur. Il correspond à un des nombres
+ d'opérateurs dans la commande <command>CREATE OPERATOR CLASS</command>.
+ Suivant les opérateurs que vous avez inclus dans la classe, le type de
+ données de <varname>query</varname> pourrait varier avec l'opérateur,
+ mais le squelette ci-dessus suppose que ce n'est pas le cas.
+ </para>
+
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><function>union</function></term>
+ <listitem>
+ <para>
+ Cette méthode consolide l'information dans l'arbre. Suivant un ensemble
+ d'entrées, cette fonction génère une nouvelle entrée d'index qui
+ représente toutes les entrées données.
+ </para>
+
+ <para>
+ La déclaration <acronym>SQL</acronym> de la fonction doit ressembler à
+ ceci :
+
+<programlisting>
+CREATE OR REPLACE FUNCTION my_union(internal, internal)
+RETURNS internal
+AS 'MODULE_PATHNAME'
+LANGUAGE C STRICT;
+</programlisting>
+
+ Et le code correspondant dans le module C peut alors suivre ce
+ squelette :
+
+<programlisting>
+Datum my_union(PG_FUNCTION_ARGS);
+PG_FUNCTION_INFO_V1(my_union);
+
+Datum
+my_union(PG_FUNCTION_ARGS)
+{
+ GistEntryVector *entryvec = (GistEntryVector *) PG_GETARG_POINTER(0);
+ GISTENTRY *ent = entryvec->vector;
+ data_type *out,
+ *tmp,
+ *old;
+ int numranges,
+ i = 0;
+
+ numranges = entryvec->n;
+ tmp = DatumGetDataType(ent[0].key);
+ out = tmp;
+
+ if (numranges == 1)
+ {
+ out = data_type_deep_copy(tmp);
+
+ PG_RETURN_DATA_TYPE_P(out);
+ }
+
+ for (i = 1; i < numranges; i++)
+ {
+ old = out;
+ tmp = DatumGetDataType(ent[i].key);
+ out = my_union_implementation(out, tmp);
+ }
+
+ PG_RETURN_DATA_TYPE_P(out);
+}
+</programlisting>
+ </para>
+
+ <para>
+ Comme vous pouvez le voir dans ce quelette, nous gérons un type de
+ données où <literal>union(X, Y, Z) = union(union(X, Y), Z)</literal>.
+ C'est assez simple pour supporter les types de données où ce n'est pas
+ le cas, en implantant un autre algorithme d'union dans cette méthode
+ de support <acronym>GiST</acronym>.
+ </para>
+
+ <para>
+ La fonction d'implantation de <function>union</function> doit renvoyer
+ un pointeur vers la mémoire qui vient d'être allouée via la fonction
+ <function>palloc()</function>. Vous ne pouvez pas tout simplement
+ renvoyer l'entrée.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><function>compress</function></term>
+ <listitem>
+ <para>
+ Convertit l'élément de données dans un format compatible avec
+ le stockage physique dans une page d'index.
+ </para>
+
+ <para>
+ La déclaration <acronym>SQL</acronym> de la fonction doit ressembler à
+ ceci :
+
+<programlisting>
+CREATE OR REPLACE FUNCTION my_compress(internal)
+RETURNS internal
+AS 'MODULE_PATHNAME'
+LANGUAGE C STRICT;
+</programlisting>
+
+ Et le code correspondant dans le module C peut alors suivre ce
+ squelette :
+
+<programlisting>
+Datum my_compress(PG_FUNCTION_ARGS);
+PG_FUNCTION_INFO_V1(my_compress);
+
+Datum
+my_compress(PG_FUNCTION_ARGS)
+{
+ GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
+ GISTENTRY *retval;
+
+ if (entry->leafkey)
+ {
+ /* replace entry->key with a compressed version */
+ compressed_data_type *compressed_data = palloc(sizeof(compressed_data_type));
+
+ /* fill *compressed_data from entry->key ... */
+
+ retval = palloc(sizeof(GISTENTRY));
+ gistentryinit(*retval, PointerGetDatum(compressed_data),
+ entry->rel, entry->page, entry->offset, FALSE);
+ }
+ else
+ {
+ /* typically we needn't do anything with non-leaf entries */
+ retval = entry;
+ }
+
+ PG_RETURN_POINTER(retval);
+}
+</programlisting>
+ </para>
+
+ <para>
+ Vous devez adapter <replaceable>compressed_data_type</replaceable> au type
+ spécifique que vous essayez d'obtenir pour compresser les nœuds
+ finaux.
+ </para>
+
+ <para>
+ Vous pourriez aussi avoir besoin de faire attention à la compression des
+ valeurs <literal>NULL</literal>, en enregistrant par exemple
+ <literal>(Datum) 0</literal> comme le fait <literal>gist_circle_compress</literal>.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><function>decompress</function></term>
+ <listitem>
+ <para>
+ L'inverse de la fonction <function>compress</function>. Convertit la
+ représentation de l'élément de donnée en un format manipulable par la base
+ de données.
+ </para>
+
+ <para>
+ La déclaration <acronym>SQL</acronym> de la fonction doit ressembler à
+ ceci :
+
+<programlisting>
+CREATE OR REPLACE FUNCTION my_decompress(internal)
+RETURNS internal
+AS 'MODULE_PATHNAME'
+LANGUAGE C STRICT;
+</programlisting>
+
+ Et le code correspondant dans le module C peut alors suivre ce
+ squelette :
+
+<programlisting>
+Datum my_decompress(PG_FUNCTION_ARGS);
+PG_FUNCTION_INFO_V1(my_decompress);
+
+Datum
+my_decompress(PG_FUNCTION_ARGS)
+{
+ PG_RETURN_POINTER(PG_GETARG_POINTER(0));
+}
+</programlisting>
+
+ Le squelette ci-dessus est convenable dans le cas iù aucune
+ décompression n'est nécessaire.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><function>penalty</function></term>
+ <listitem>
+ <para>
+ Renvoie une valeur indiquant le <quote>coût</quote> d'insertion
+ d'une nouvelle entrée dans une branche particulière de l'arbre. Les
+ éléments seront insérés dans l'ordre des pénalités moindres
+ (<function>penalty</function>) de l'arbre.
+ </para>
+
+ <para>
+ La déclaration <acronym>SQL</acronym> de la fonction doit ressembler à
+ ceci :
+
+<programlisting>
+CREATE OR REPLACE FUNCTION my_penalty(internal, internal, internal)
+RETURNS internal
+AS 'MODULE_PATHNAME'
+LANGUAGE C STRICT; -- in some cases penalty functions need not be strict
+</programlisting>
+
+ Et le code correspondant dans le module C peut alors suivre ce
+ squelette :
+
+<programlisting>
+Datum my_penalty(PG_FUNCTION_ARGS);
+PG_FUNCTION_INFO_V1(my_penalty);
+
+Datum
+my_penalty(PG_FUNCTION_ARGS)
+{
+ GISTENTRY *origentry = (GISTENTRY *) PG_GETARG_POINTER(0);
+ GISTENTRY *newentry = (GISTENTRY *) PG_GETARG_POINTER(1);
+ float *penalty = (float *) PG_GETARG_POINTER(2);
+ data_type *orig = DatumGetDataType(origentry->key);
+ data_type *new = DatumGetDataType(newentry->key);
+
+ *penalty = my_penalty_implementation(orig, new);
+ PG_RETURN_POINTER(penalty);
+}
+</programlisting>
+ </para>
+
+ <para>
+ La fonction <function>penalty</function> est crucial pour de bonnes
+ performances de l'index. Elle sera utilisée lors de l'insertion pour
+ déterminer la branche à suivre pour savoir où ajoter la nouvelle entrée
+ dans l'arbre. Lors de l'exécution de la requête, plus l'arbre sera bien
+ balancé, plus l'exécution sera rapide.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><function>picksplit</function></term>
+ <listitem>
+ <para>
+ Quand une division de page est nécessaire pour un index, cette fonction
+ décide des entrées de la page qui resteront sur l'ancienne page et de
+ celles qui seront déplacées sur la nouvelle page.
+ </para>
+
+ <para>
+ La déclaration <acronym>SQL</acronym> de la fonction doit ressembler à
+ ceci :
+
+<programlisting>
+CREATE OR REPLACE FUNCTION my_picksplit(internal, internal)
+RETURNS internal
+AS 'MODULE_PATHNAME'
+LANGUAGE C STRICT;
+</programlisting>
+
+ Et le code correspondant dans le module C peut alors suivre ce
+ squelette :
+
+<programlisting>
+Datum my_picksplit(PG_FUNCTION_ARGS);
+PG_FUNCTION_INFO_V1(my_picksplit);
+
+Datum
+my_picksplit(PG_FUNCTION_ARGS)
+{
+ GistEntryVector *entryvec = (GistEntryVector *) PG_GETARG_POINTER(0);
+ OffsetNumber maxoff = entryvec->n - 1;
+ GISTENTRY *ent = entryvec->vector;
+ GIST_SPLITVEC *v = (GIST_SPLITVEC *) PG_GETARG_POINTER(1);
+ int i,
+ nbytes;
+ OffsetNumber *left,
+ *right;
+ data_type *tmp_union;
+ data_type *unionL;
+ data_type *unionR;
+ GISTENTRY **raw_entryvec;
+
+ maxoff = entryvec->n - 1;
+ nbytes = (maxoff + 1) * sizeof(OffsetNumber);
+
+ v->spl_left = (OffsetNumber *) palloc(nbytes);
+ left = v->spl_left;
+ v->spl_nleft = 0;
+
+ v->spl_right = (OffsetNumber *) palloc(nbytes);
+ right = v->spl_right;
+ v->spl_nright = 0;
+
+ unionL = NULL;
+ unionR = NULL;
+
+ /* Initialize the raw entry vector. */
+ raw_entryvec = (GISTENTRY **) malloc(entryvec->n * sizeof(void *));
+ for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i))
+ raw_entryvec[i] = &(entryvec->vector[i]);
+
+ for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i))
+ {
+ int real_index = raw_entryvec[i] - entryvec->vector;
+
+ tmp_union = DatumGetDataType(entryvec->vector[real_index].key);
+ Assert(tmp_union != NULL);
+
+ /*
+ * Choose where to put the index entries and update unionL and unionR
+ * accordingly. Append the entries to either v_spl_left or
+ * v_spl_right, and care about the counters.
+ */
+
+ if (my_choice_is_left(unionL, curl, unionR, curr))
+ {
+ if (unionL == NULL)
+ unionL = tmp_union;
+ else
+ unionL = my_union_implementation(unionL, tmp_union);
+
+ *left = real_index;
+ ++left;
+ ++(v->spl_nleft);
+ }
+ else
+ {
+ /*
+ * Same on the right
+ */
+ }
+ }
+
+ v->spl_ldatum = DataTypeGetDatum(unionL);
+ v->spl_rdatum = DataTypeGetDatum(unionR);
+ PG_RETURN_POINTER(v);
+}
+</programlisting>
+ </para>
+
+ <para>
+ Comme <function>penalty</function>, la fonction <function>picksplit</function>
+ est cruciale pour de bonnes performances de l'index. Concevoir des
+ implantations convenables des fonctions <function>penalty</function> et
+ <function>picksplit</function> est le challenge d'un index
+ <acronym>GiST</acronym> performant.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><function>same</function></term>
+ <listitem>
+ <para>
+ Renvoit true si les deux entrées de l'index sont identiques, faux sinon.
+ </para>
+
+ <para>
+ La déclaration <acronym>SQL</acronym> de la fonction ressemble à
+ ceci :
+
+<programlisting>
+CREATE OR REPLACE FUNCTION my_same(internal, internal, internal)
+RETURNS internal
+AS 'MODULE_PATHNAME'
+LANGUAGE C STRICT;
+</programlisting>
+
+ Et le code correspondant dans le module C peut alors suivre ce
+ squelette :
+
+<programlisting>
+Datum my_same(PG_FUNCTION_ARGS);
+PG_FUNCTION_INFO_V1(my_same);
+
+Datum
+my_same(PG_FUNCTION_ARGS)
+{
+ prefix_range *v1 = PG_GETARG_PREFIX_RANGE_P(0);
+ prefix_range *v2 = PG_GETARG_PREFIX_RANGE_P(1);
+ bool *result = (bool *) PG_GETARG_POINTER(2);
+
+ *result = my_eq(v1, v2);
+ PG_RETURN_POINTER(result);
+}
+</programlisting>
+
+ Pour des raisons historiques, la fonction <function>same</function> ne
+ renvoie pas seulement un résultat booléen ; à la place, il doit
+ enregistrer le drapeau à l'emplacement indiqué par le troisième argument.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ </variablelist>
+
+</sect1>
+
+<sect1 id="gist-examples">
+ <title>Exemples</title>
+
+ <para>
+ La distribution source de <productname>PostgreSQL</productname> inclut
+ plusieurs exemples de méthodes d'indexation implantées selon
+ <acronym>GiST</acronym>. Le système principal fournit des fonctionnalités
+ de recherche plein texte (indexation des <type>tsvector</type> et
+ <type>tsquery</type>) ainsi que des fonctionnalités équivalentes aux R-Tree
+ pour certains types de données géométriques
+ (voir <filename>src/backend/access/gist/gistproc.c</filename>). Les modules
+ <filename>contrib</filename> suivants contiennent aussi des classes d'opérateur
+ <acronym>GiST</acronym> :
+ </para>
+
+ <variablelist>
+ <varlistentry>
+ <term>btree_gist</term>
+ <listitem>
+ <para>Fonctionnalités équivalentes aux B-Tree pour plusieurs types de
+ données</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>cube</term>
+ <listitem>
+ <para>Indexation de cubes multi-dimensionnels</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>hstore</term>
+ <listitem>
+ <para>Module pour le stockage des paires (clé, valeur)</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>intarray</term>
+ <listitem>
+ <para>RD-Tree pour tableaux uni-dimensionnels de valeurs int4</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>ltree</term>
+ <listitem>
+ <para>Indexation des structures de type arbre</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>pg_trgm</term>
+ <listitem>
+ <para>Similarité textuelle par correspondance de trigrammes</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>seg</term>
+ <listitem>
+ <para>Indexation pour les <quote>nombres
+ flottants</quote></para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+
+</sect1>
+
+<sect1 id="gist-recovery">
+ <title>Récupération après un arrêt brutal</title>
+
+ <para>
+ Il est généralement suffisant de rejouer les traces WAL pour restaurer l'intégrité d'un
+ index GiST après un arrêt brutal de la base de données. Néanmoins, il existe
+ quelques cas particuliers pour lesquels l'état de l'index n'est pas
+ entièrement reconstruit. L'index reste fonctionnellement correct mais
+ les performances peuvent se trouver dégradées. Lorsque cela
+ arrive, l'index peut être réparé par <command>VACUUM</command> de sa table, ou
+ par reconstruction avec <command>REINDEX</command>. Dans certains cas, un simple
+ <command>VACUUM</command> ne suffit pas et un <command>VACUUM FULL</command>
+ ou un <command>REINDEX</command> est nécessaire. Ce besoin est indiqué par
+ la survenue d'un tel message :
+<programlisting>LOG: index NNN/NNN/NNN needs VACUUM or REINDEX to finish crash recovery
+</programlisting>
+ ou le message suivant lors d'insertions dans l'index :
+<programlisting>LOG: index "FOO" needs VACUUM or REINDEX to finish crash recovery
+</programlisting>
+ Si un simple <command>VACUUM</command> est incapable de réaliser
+ complètement la récupération, l'avertissement suivant est envoyé :
+<programlisting>NOTICE: index "FOO" needs VACUUM FULL or REINDEX to finish crash recovery
+</programlisting>
+ </para>
+</sect1>
+
+</chapter>
Deleted: traduc/tags/tv840rc2/storage.xml
===================================================================
--- traduc/trunk/postgresql/storage.xml 2009-06-23 22:14:31 UTC (rev 1352)
+++ traduc/tags/tv840rc2/storage.xml 2009-06-27 10:41:54 UTC (rev 1355)
@@ -1,867 +0,0 @@
-<?xml version="1.0" encoding="ISO-8859-15"?>
-<!-- Dernière modification
- le $Date$
- par $Author$
- révision $Revision$ -->
-
-<chapter id="storage">
-
-<title>Stockage physique de la base de données</title>
-
-<para>
-Ce chapitre fournit un aperçu du format de stockage physique utilisé par les
-bases de données <productname>PostgreSQL</productname>.
-</para>
-
-<sect1 id="storage-file-layout">
-
-<title>Emplacement des fichiers de la base de données</title>
-
-<para>
-Cette section décrit le format de stockage au niveau des fichiers et
-répertoires.
-</para>
-
-<para>
-Toutes les données nécessaires à un groupe de bases de données sont stockées
-dans le répertoire data du groupe, habituellement référencé en tant que
-<varname>PGDATA</varname> (d'après le nom de la variable d'environnement qui peut
-être utilisé pour le définir). Un emplacement courant pour <varname>PGDATA</varname>
-est <filename>/var/lib/pgsql/data</filename>. Plusieurs groupes, gérés par différentes
-instances du serveur, peuvent exister sur la même machine.
-</para>
-
-<para>
-Le répertoire <varname>PGDATA</varname> contient plusieurs sous-répertoires et
-fichiers de contrôle, comme indiqué dans le <xref linkend="pgdata-contents-table"/>.
-En plus de ces éléments requis, les fichiers
-de configuration du groupe, <filename>postgresql.conf</filename>,
-<filename>pg_hba.conf</filename> et <filename>pg_ident.conf</filename> sont
-traditionnellement stockés dans <varname>PGDATA</varname> (bien qu'il soit possible de
-les conserver ailleurs à partir de la version 8.0 de
-<productname>PostgreSQL</productname>).
-</para>
-
-<table tocentry="1" id="pgdata-contents-table">
-<title>Contenu de <varname>PGDATA</varname></title>
-<tgroup cols="2">
-<colspec colnum="1" colwidth="0.5*"/>
-<colspec colnum="2" colwidth="1.5*"/>
-<thead>
-<row>
-<entry>Élément</entry>
-<entry>Description</entry>
-</row>
-</thead>
-
-<tbody>
-
-<row>
- <entry><filename>PG_VERSION</filename></entry>
- <entry>Un fichier contenant le numéro de version majeur de
- <productname>PostgreSQL</productname></entry>
-</row>
-
-<row>
- <entry><filename>base</filename></entry>
- <entry>Sous-répertoire contenant les sous-répertoires par base de
- données</entry>
-</row>
-
-<row>
- <entry><filename>global</filename></entry>
- <entry>Sous-répertoire contenant les tables communes au groupe, telles que
- <structname>pg_database</structname></entry>
-</row>
-
-<row>
- <entry><filename>pg_clog</filename></entry>
- <entry>Sous-répertoire contenant les données d'état de validation des
- transactions</entry>
-</row>
-
-<row>
- <entry><filename>pg_multixact</filename></entry>
- <entry>Sous-répertoire contenant des données sur l'état des
- multi-transactions (utilisé pour les verrous de lignes partagées)</entry>
-</row>
-
-<row>
- <entry><filename>pg_stat_tmp</filename></entry>
- <entry>Sous-répertoire contenant les fichiers temporaires pour le sous-système
- des statistiques</entry>
-</row>
-
-<row>
- <entry><filename>pg_subtrans</filename></entry>
- <entry>Sous-répertoire contenant les données d'états des
- sous-transaction</entry>
-</row>
-
-<row>
- <entry><filename>pg_tblspc</filename></entry>
- <entry>Sous-répertoire contenant les liens symboliques vers les espaces
- logiques</entry>
-</row>
-
-<row>
- <entry><filename>pg_twophase</filename></entry>
- <entry>Sous-répertoire contenant les fichiers d'état pour les transactions
- préparées</entry>
-</row>
-
-<row>
- <entry><filename>pg_xlog</filename></entry>
- <entry>Sous-répertoire contenant les fichiers WAL (Write Ahead Log)</entry>
-</row>
-
-<row>
- <entry><filename>postmaster.opts</filename></entry>
- <entry>Un fichier enregistrant les options en ligne de commande avec
- lesquelles le serveur a été lancé la dernière fois</entry>
-</row>
-
-<row>
- <entry><filename>postmaster.pid</filename></entry>
- <entry>Un fichier verrou enregistrant le PID courant du serveur et l'identifiant
- du segment de mémoire partagé (absent après l'arrêt du serveur)</entry>
-</row>
-
-</tbody>
-</tgroup>
-</table>
-
-<para>
-Pour chaque base de données dans le groupe, il existe un sous-répertoire dans
-<varname>PGDATA</varname><filename>/base</filename>, nommé d'après l'OID de la base de données
-dans <structname>pg_database</structname>. Ce sous-répertoire est l'emplacement par
-défaut pour les fichiers de la base de données; en particulier, ses
-catalogues système sont stockés ici.
-</para>
-
-<para>
-Chaque table et index sont stockés dans un fichier séparé, nommé d'après le
-numéro <firstterm>filenode</firstterm> de la table ou de l'index, lequel se
-trouve dans <structname>pg_class</structname>.<structfield>relfilenode</structfield>.
-En plus du fichier principal (appelé aussi « main fork »), chaque
-table et index a une <firstterm>carte des espaces libres</firstterm> (voir
-<xref linkend="storage-fsm"/>), qui stocke des informations sur les emplacements
-libres dans la relation. La carte des espace libre est stockée dans un fichier
-nommé par le numéro relfilenode à qui est ajouté le suffixe
-<literal>_fsm</literal>. Les tables ont aussi un fichier pour la <firstterm>carte de
-visibilité</firstterm>, de suffixe <literal>_vm</literal>, pour tracer les pages connues
-pour n'avoir aucune ligne morte.
-La carte de visibilité est décrite plus bas dans <xref linkend="storage-vm"/>.
-</para>
-
-<caution>
-<para>
-Notez que, bien que le filenode de la table correspond souvent à son OID,
-cela n'est <emphasis>pas</emphasis> nécessairement le cas; certaines
-opérations, comme <command>TRUNCATE</command>, <command>REINDEX</command>,
-<command>CLUSTER</command> et quelques formes d'<command>ALTER TABLE</command>, peuvent
-modifier le filenode tout en préservant l'OID. Évitez de supposer que filenode
-et OID sont identiques.
-</para>
-</caution>
-
-<para>
-Quand une table ou un index dépasse 1 Go, il est divisé en
-<firstterm>segments</firstterm> d'un Go. Le nom du fichier du premier
-segment est identique au filenode ; les segments suivants sont nommés
-filenode.1, filenode.2, etc. Cette disposition évite des problèmes sur les
-plateformes qui ont des limitations sur les tailles des fichiers.
-(Actuellement, 1 Go est la taille du segment par défaut. Cette taille est
-ajustable en utilisant l'option <option>--with-segsize</option> pour configure
-avant de construire <productname>PostgreSQL</productname>.)
-En principe, les fichiers de la carte des espaces libres et de la carte de
-visibilité pourraient aussi nécessiter plusieurs segments, bien qu'il y a
-peu de chance que cela arrive réellement.
-Le contenu des tables et des index est discuté plus
-en détails dans <xref linkend="storage-page-layout"/>.
-</para>
-
-<para>
-Une table contenant des colonnes avec des entrées potentiellement volumineuses
-aura une table <firstterm>TOAST</firstterm> associée, qui est
-utilisée pour le stockage de valeurs de champs trop importantes pour
-conserver des lignes adéquates.
-<structname>pg_class</structname>.<structfield>reltoastrelid</structfield> établit un lien entre
-une table et sa table <acronym>TOAST</acronym>, si elle existe. Voir <xref
-linkend="storage-toast"/> pour plus d'informations.
-</para>
-
-<para>
-Les tablespaces rendent ce scénario plus compliqués. Chaque espace
-logique défini par l'utilisateur contient un lien symbolique dans le répertoire
-<varname>PGDATA</varname><filename>/pg_tblspc</filename>, pointant vers le répertoire physique
-du tablespace (comme spécifié dans sa commande <command>CREATE
-TABLESPACE</command>). Le lien symbolique est nommé d'après l'OID du tablespace.
-À l'intérieur du répertoire du tablespace, il existe un sous-répertoire
-pour chacune des bases de données contenant des éléments dans ce tablespace. Ce
-sous-répertoire est nommé d'après l'OID de la base. Les tables de
-ce répertoire suivent le schéma de nommage des filenodes. Le tablespace
-<literal>pg_default</literal> n'est pas accédé via <filename>pg_tblspc</filename> mais
-correspond à <varname>PGDATA</varname><filename>/base</filename>. De façon similaire,
-le tablespace <literal>pg_global</literal> n'est pas accédé via
-<filename>pg_tblspc</filename> mais correspond à <varname>PGDATA</varname><filename>/global</filename>.
-</para>
-
-<para>
-Les fichiers temporaires (pour des opérations comme le tri de plus de données
-que ce que la mémoire peut contenir) sont créés à l'intérieur de <varname>PGDATA</varname><filename>/base/pgsql_tmp</filename>,
-ou dans un sous-répertoire <filename>pgsql_tmp</filename> du répertoire du
-tablespace si un tablespace autre que <literal>pg_default</literal> est
-indiqué pour eux. Le nom du fichier temporaire est de la forme
-<filename>pgsql_tmp<replaceable>PPP</replaceable>.<replaceable>NNN</replaceable></filename>,
-où <replaceable>PPP</replaceable> est le PID du serveur propriétaire et
-<replaceable>NNN</replaceable> distingue les différents fichiers temporaires de ce
-serveur.
-</para>
-
-</sect1>
-
-<sect1 id="storage-toast">
-
-<title>TOAST</title>
-
- <indexterm>
- <primary>TOAST</primary>
- </indexterm>
- <indexterm><primary>sliced bread</primary><see>TOAST</see></indexterm>
-
-<para>
-Cette section fournit un aperçu de <acronym>TOAST</acronym> (<foreignphrase>The
-Oversized-Attribute Storage Technique</foreignphrase>, la technique de
-stockage des attributs trop grands).
-</para>
-
-<para>
-Puisque <productname>PostgreSQL</productname> utilise une taille de page fixe
-(habituellement 8 Ko) et n'autorise pas qu'une ligne s'étende sur plusieurs
-pages. Du coup, il n'est pas possible de stocker de grandes valeurs directement
-dans les champs. Pour dépasser cette limitation, les valeurs de champ
-volumineuses sont compressées et/ou divisées en plusieurs lignes physiques. Ceci
-survient de façon transparente pour l'utilisateur, avec seulement un petit
-impact sur le code du serveur. Cette technique est connu sous l'acronyme
-affectueux de <acronym>TOAST</acronym> (ou <quote>the best thing since sliced
-bread</quote>).
-</para>
-
-<para>
-Seuls certains types de données supportent <acronym>TOAST</acronym> — il n'est
-pas nécessaire d'imposer cette surcharge sur les types de données qui ne
-produisent pas de gros volumes. Pour supporter
-<acronym>TOAST</acronym>, un type de données doit avoir une représentation
-(<firstterm>varlena</firstterm>) à longueur variable, dans laquelle les 32 premiers bits
-contiennent la longueur totale de la valeur en octets (ceci incluant la
-longueur elle-même). <acronym>TOAST</acronym> n'a aucune contrainte supplémentaire
-sur la représentation. Toutes les fonctions niveau C qui gèrent un type données
-supportant <acronym>TOAST</acronym> doivent faire attention à gérer les valeurs en
-entrée <acronym>TOAST</acronym>ées. (Ceci se fait normalement en appelant
-<function>PG_DETOAST_DATUM</function> avant de faire quoi que ce soit avec une valeur
-en entrée; mais dans certains cas, des approches plus efficaces sont possibles.)
-</para>
-
-<para>
-<acronym>TOAST</acronym> récupère deux bits du mot contenant la longueur
-d'un varlena (ceux de poids fort sur les machines big-endian, ceux de poids
-faible sur les machines little-endian), limitant du coup la taille logique
-de toute valeur d'un type de données <acronym>TOAST</acronym> à 1 Go
-(2<superscript>30</superscript> - 1 octets). Quand les deux bits sont à
-zéro, la valeur est une valeur non <acronym>TOAST</acronym>é du type de
-données et les bits restants dans le mot contenant la longueur indique
-la taille total du datum (incluant ce mot) en octets. Quand le bit de poids
-fort (ou de poids faible) est à un, la valeur a un en-tête de seulement
-un octet alors qu'un en-tête normal en fait quatre. Les bits restants
-donne la taille total du datum (incluant ce mot) en octets. Il reste un
-cas spécial : si les bits restants sont tous à zéro (ce qui est
-impossible étant donné que le mot indiquant la longueur est inclut dans
-la taille), la valeur est un pointeur vers une donnée stockée dans une table
-TOAST séparée (la taille d'un pointeur TOAST est indiquée dans le second
-octet du datum). Les valeurs dont l'en-tête fait un seul octet ne sont pas
-alignées sur une limite particulière. Enfin, quand le bit de poids fort
-(ou de poids faible) est supprimé mais que le bit adjacent vaut un, le
-contenu du datum est compressé et doit être décompresser avant utilisation.
-Dans ce cas, les bits restants du mot contenant la longueur indiquent la
-taille totale du datum compressé, pas celles des données au départ. Notez
-que la compression est aussi possible pour les données de la table TOAST
-mais l'en-tête varlena n'indique pas si c'est le cas — le contenu
-du pointeur TOAST le précise.
-</para>
-
-<para>
-Si une des colonnes d'une table est <acronym>TOAST</acronym>-able, la table disposera
-d'une table <acronym>TOAST</acronym> associé, dont l'OID est stockée dans l'entrée
-<structname>pg_class</structname>.<structfield>reltoastrelid</structfield> de la table. Les valeurs
-<acronym>TOAST</acronym>ées hors-ligne sont conservées dans la table <acronym>TOAST</acronym>
-comme décrit avec plus de détails ci-dessous.
-</para>
-
-<para>
-La technique de compression utilisée est un simple et rapide membre de la
-famille des techniques de compression LZ. Voir <filename>src/backend/utils/adt/pg_lzcompress.c</filename> pour les
-détails.
-</para>
-
-<para>
-Les valeurs hors-ligne sont divisées (après compression si nécessaire) en
-morceaux d'au plus <literal>TOAST_MAX_CHUNK_SIZE</literal> octets (par défaut,
-cette valeur est choisie pour que quatre morceaux de ligne tiennent sur une
-page, d'où les 2000 octets). Chaque morceau est stocké comme une ligne séparée dans la table
-<acronym>TOAST</acronym> de la table propriétaire. Chaque table <acronym>TOAST</acronym>
-contient les colonnes <structfield>chunk_id</structfield> (un OID identifiant la valeur
-<acronym>TOAST</acronym>ée particulière), <structfield>chunk_seq</structfield> (un numéro de
-séquence pour le morceau de la valeur) et <structfield>chunk_data</structfield> (la donnée
-réelle du morceau). Un index unique sur <structfield>chunk_id</structfield> et
-<structfield>chunk_seq</structfield> offre une récupération rapide des valeurs. Un
-pointeur datum représentant une valeur <acronym>TOAST</acronym>ée hors-ligne a par conséquent
-besoin de stocker l'OID de la table <acronym>TOAST</acronym> dans laquelle chercher
-et l'OID de la valeur spécifique (son <structfield>chunk_id</structfield>). Par commodité,
-les pointeurs datums stockent aussi la taille logique du datum (taille
-de la donnée originale non compressée) et la taille stockée réelle (différente
-si la compression a été appliquée). À partir des octets d'en-tête varlena,
-la taille totale d'un pointeur datum <acronym>TOAST</acronym> est par conséquent de 18 octets
-quelque soit la taille réelle de la valeur représentée.
-</para>
-
-<para>
-Le code <acronym>TOAST</acronym> est déclenché seulement quand une valeur de ligne
-à stocker dans une table est plus grande que <symbol>TOAST_TUPLE_THRESHOLD</symbol> octets (habituellement
-2 Ko). Le code <acronym>TOAST</acronym> compressera et/ou déplacera les valeurs
-de champ hors la ligne jusqu'à ce que la valeur de la ligne soit plus petite que
-<symbol>TOAST_TUPLE_TARGET</symbol> octets (habituellement là-aussi
-2 Ko) ou que plus aucun gain ne puisse être réalisé.
-Lors d'une opération UPDATE, les valeurs des champs non modifiées sont habituellement
-préservées telles quelles ; donc un UPDATE sur une ligne avec des valeurs hors
-ligne n'induit pas de coûts à cause de <acronym>TOAST</acronym> si aucune des valeurs
-hors-ligne n'est modifiée.
-</para>
-
-<para>
-Le code <acronym>TOAST</acronym> connaît quatre stratégies différentes pour stocker
-les colonnes <acronym>TOAST</acronym>-ables :
-
- <itemizedlist>
- <listitem>
- <para>
- <literal>PLAIN</literal> empêche soit la compression soit le stockage
- hors-ligne ; de plus, il désactive l'utilisation d'en-tête sur
- un octet pour les types varlena. Ceci est la seule stratégie possible
- pour les colonnes des types de données non
- <acronym>TOAST</acronym>-ables.
- </para>
- </listitem>
- <listitem>
- <para>
- <literal>EXTENDED</literal> permet à la fois la compression et le
- stockage hors-ligne. Ceci est la valeur par défaut de la plupart des
- types de données <acronym>TOAST</acronym>-ables. La compression sera tentée en
- premier, ensuite le stockage hors-ligne si la ligne est toujours trop
- grande.
- </para>
- </listitem>
- <listitem>
- <para>
- <literal>EXTERNAL</literal> autorise le stockage hors-ligne mais pas la
- compression. L'utilisation d'<literal>EXTERNAL</literal> rendra plus rapides les
- opérations sur des sous-chaînes d'importantes colonnes de type
- <type>text</type> et <type>bytea</type> (au dépens d'un
- espace de stockage accrus) car ces opérations sont optimisées pour
- récupérer seulement les parties requises de la valeur hors-ligne
- lorsqu'elle n'est pas compressée.
- </para>
- </listitem>
- <listitem>
- <para>
- <literal>MAIN</literal> autorise la compression mais pas le stockage
- hors-ligne. (En réalité le stockage hors-ligne sera toujours réalisé
- pour de telles colonnes mais seulement en dernier ressort s'il n'existe
- aucune autre solution pour diminuer suffisamment la taille de la ligne.)
- </para>
- </listitem>
- </itemizedlist>
-
-Chaque type de données <acronym>TOAST</acronym>-able spécifie une stratégie par défaut
-pour les colonnes de ce type de donnée, mais la stratégie pour une colonne d'une table
-donnée peut être modifiée avec <command>ALTER TABLE SET STORAGE</command>.
-</para>
-
-<para>
-Cette combinaison a de nombreux avantages comparés à une approche plus directe
-comme autoriser le stockage des valeurs de lignes sur plusieurs pages. En
-supposant que les requêtes sont habituellement qualifiées par comparaison avec
-des valeurs de clé relativement petites, la grosse partie du travail de
-l'exécuteur sera réalisée en utilisant l'entrée principale de la ligne. Les
-grandes valeurs des attributs <acronym>TOAST</acronym>és seront seulement récupérées
-(si elles sont sélectionnées) au moment où l'ensemble de résultats est
-envoyé au client. Ainsi, la table principale est bien plus petite
-et un plus grand nombre de ses lignes tiennent dans le cache du tampon partagé,
-ce qui ne serait pas le cas sans aucun stockage hors-ligne.
-Le tri l'utilise aussi, et les tris seront plus souvent réalisés entièrement
-en mémoire. Un petit test a montré qu'une table contenant des pages HTML
-typiques ainsi que leurs URL étaient stockées en à peu près la moitié de la
-taille des données brutes en incluant la table <acronym>TOAST</acronym> et que la
-table principale contenait moins de 10 % de la totalité des données (les
-URL et quelques petites pages HTML). Il n'y avait pas de différence à l'exécution
-en comparaison avec une table non <acronym>TOAST</acronym>ée, dans laquelle toutes les
-pages HTLM avaient été coupées à 7 Ko pour tenir.
-</para>
-
-</sect1>
-
-<sect1 id="storage-fsm">
-
-<title>Carte des espaces libres</title>
-
-<indexterm>
- <primary>Free Space Map</primary>
-</indexterm>
-<indexterm><primary>FSM</primary><see>Free Space Map</see></indexterm>
-
-<para>
-Chaque table et index, en dehors des index hash, a une carte des espaces libres
-(appelée aussi <acronym>FSM</acronym>, acronyme de <foreignphrase>Free Space
-Map</foreignphrase>) pour conserver le trace des emplacements disponibles dans
-la relation. Elle est stockée dans un fichier séparé du fichier des données. Le
-nom de fichier est le numéro relfilenode suivi du suffixe
-<literal>_fsm</literal>. Par exemple, si le relfilenode d'une relation est
-12345, la FSM est stockée dans un fichier appelé
-<filename>12345_fsm</filename>, dans même répertoire que celui utilisé pour le
-fichier des données.
-</para>
-
-<para>
-La carte des espaces libres est organisée comme un arbre de pages
-<acronym>FSM</acronym>. Les pages <acronym>FSM</acronym> de niveau bas stockent
-l'espace libre disponible dans chaque page de la relation. Les niveaux
-suppérieurs agrégent l'information des niveaux bas.
-</para>
-
-<para>
-À l'intérieur de chaque page <acronym>FSM</acronym> se trouve un arbre binaire
-stocké dans un tableau avec un octet par nœud. Chaque nœud final
-représente une page de la relation, ou une page FSM de niveau bas. Dans chaque
-nœud non final, la valeur la plus haute des valeurs enfants est stockée.
-Du coup, la valeur maximum de tous les nœuds se trouve à la racine.
-</para>
-
-<para>
-Voir <filename>src/backend/storage/freespace/README</filename> pour plus de
-détails sur la façon dont la <acronym>FSM</acronym> est structurée, et comment
-elle est mise à jour et recherchée. Le module contrib
-<filename>contrib/pg_freespacemap</filename> peut être utilisé pour examiner
-l'information stockée dans les cartes d'espace libre (voir <xref
-linkend="pgfreespacemap"/>).
-</para>
-
-</sect1>
-
-<sect1 id="storage-vm">
-
-<title>Visibility Map</title>
-
-<indexterm>
- <primary>Visibility Map</primary>
-</indexterm>
-<indexterm><primary>VM</primary><see>Visibility Map</see></indexterm>
-
-<para>
-Each heap relation has a Visibility Map
-(VM) to keep track of which pages contain only tuples that are known to be
-visible to all active transactions. It's stored
-alongside the main relation data in a separate relation fork, named after the
-filenode number of the relation, plus a <literal>_vm</literal> suffix. For example,
-if the filenode of a relation is 12345, the VM is stored in a file called
-<filename>12345_vm</filename>, in the same directory as the main relation file.
-Note that indexes do not have VMs.
-</para>
-
-<para>
-The visibility map simply stores one bit per heap page. A set bit means
-that all tuples on the page are known to be visible to all transactions.
-This means that the page does not contain any tuples that need to be vacuumed;
-in future it might also be used to avoid visiting the page for visibility
-checks. The map is conservative in the sense that we
-make sure that whenever a bit is set, we know the condition is true, but if
-a bit is not set, it might or might not be true.
-</para>
-
-</sect1>
-
-<sect1 id="storage-page-layout">
-
-<title>Emplacement des pages de la base de données</title>
-
-<para>
-Cette section fournit un aperçu du format des pages utilisées par les tables et
-index de <productname>PostgreSQL</productname>.<footnote>
- <para>
- En réalité, les méthodes d'accès par index n'ont pas besoin d'utiliser ce
- format de page. Toutes les méthodes d'indexage existantes utilisent ce
- format de base mais les données conservées dans les métapages des index
- ne suivent habituellement pas les règles d'emplacement des éléments.
- </para>
-</footnote>
-Les séquences et les tables <acronym>TOAST</acronym> tables sont formatées comme des
-tables standards.
-</para>
-
-<para>
-Dans l'explication qui suit, un <firstterm>octet</firstterm> contient huit
-bits. De plus, le terme <firstterm>élément</firstterm> fait référence à une
-valeur de données individuelle qui est stockée dans une page. Dans une table,
-un élément est une ligne ; dans un index, un élément est une entrée
-d'index.
-</para>
-
-<para>
-Chaque table et index est stocké comme un tableau de <firstterm>pages</firstterm> d'une
-taille fixe (habituellement 8 Ko, bien qu'une taille de page différente
-peut être sélectionnée lors de la compilation du serveur). Dans une table,
-toutes les pages sont logiquement équivalentes pour qu'un élément (ligne)
-particulier puisse être stocké dans n'importe quelle page. Dans les index, la
-première page est généralement réservée comme <firstterm>métapage</firstterm> contenant
-des informations de contrôle, et il peut exister différents types de pages à
-l'intérieur de l'index, suivant la méthode d'accès à l'index. Les tables ont
-aussi une carte de visibilité dans un fichier de suffixe <literal>_vm</literal>,
-pour tracer les pages dont on sait qu'elles ne contiennent pas de lignes mortes
-et qui n'ont pas du coup besoin de VACUUM.
-</para>
-
-<para>
-<xref linkend="page-table"/> affiche le contenu complet d'une page. Il existe
-cinq parties pour chaque page.
-</para>
-
-<table tocentry="1" id="page-table">
-<title>Disposition générale d'une page</title>
-<titleabbrev>Disposition d'une page</titleabbrev>
-<tgroup cols="2">
-<colspec colnum="1" colwidth="0.5*"/>
-<colspec colnum="2" colwidth="1.5*"/>
-<thead>
-<row>
-<entry>Élément</entry>
-<entry>Description</entry>
-</row>
-</thead>
-
-<tbody>
-
-<row>
- <entry>PageHeaderData</entry>
- <entry>Longueur de 24 octets. Contient des informations générales sur la page y compris
- des pointeurs sur les espaces libres.</entry>
-</row>
-
-<row>
- <entry>ItemIdData</entry>
- <entry>Tableau de paires (décalage,longueur) pointant sur les éléments réels.
- Quatre octets par élément.</entry>
-</row>
-
-<row>
- <entry>Free space</entry>
- <entry>L'espace non alloué. Les pointeurs de nouveaux éléments sont alloués
- à partir du début de cette région, les nouveaux éléments à partir de la
- fin.</entry>
-</row>
-
-<row>
- <entry>Items</entry>
- <entry>Les éléments eux-mêmes.</entry>
-</row>
-
-<row>
- <entry>Special space</entry>
- <entry>Données spécifiques des méthodes d'accès aux index. Différentes
- méthodes stockent différentes données. Vide pour les tables
- ordinaires.</entry>
-</row>
-
-</tbody>
-</tgroup>
-</table>
-
- <para>
-
- Les 24 premiers octets de chaque page consistent en un en-tête de page
- (PageHeaderData). Son format est détaillé dans <xref
- linkend="pageheaderdata-table"/>. Les deux premiers champs traquent l'entrée
- WAL la plus récente relative à cette page. Ensuite se trouve un champ de
- deux octets contenant des drapeaux. Ils sont suivis par trois
- champs d'entiers sur deux octets (<structfield>pd_lower</structfield>,
- <structfield>pd_upper</structfield> et
- <structfield>pd_special</structfield>). Ils contiennent des décalages
- d'octets à partir du début de la page jusqu'au début de l'espace non alloué,
- jusqu'à la fin de l'espace non alloué, et jusqu'au début de l'espace spécial.
- Les deux octets suivants de l'en-tête de page,
- <structfield>pd_pagesize_version</structfield>, stockent à la fois la taille
- de la page et un indicateur de versoin. À partir de la version 8.3 de
- <productname>PostgreSQL</productname>, le numéro de version est 4 ;
- <productname>PostgreSQL</productname> 8.1 et 8.2 ont utilisé le numéro de version 3 ;
- <productname>PostgreSQL</productname> 8.0 a utilisé le numéro de version 2 ;
- <productname>PostgreSQL</productname> 7.3 et 7.4 ont utilisé le numéro de
- version 1 ; les versions précédentes utilisaient le numéro de version 0.
- (La disposition fondamentale de la page et le format de l'en-tête n'ont pas changé
- dans la plupart de ces versions mais la disposition de l'en-tête des lignes de tête a
- changé.) La taille de la page est seulement présente comme vérification
- croisée ; il n'existe pas de support pour avoir plus d'une taille de
- page dans une installation.
- Le dernier champ est une aide indiquant si traiter la page serait
- profitable : il garde l'information sur le plus vieux XMAX non traité
- de la page.
- </para>
-
- <table tocentry="1" id="pageheaderdata-table">
- <title>Disposition de PageHeaderData</title>
- <titleabbrev>Disposition de PageHeaderData</titleabbrev>
- <tgroup cols="4">
- <colspec colnum="1" colwidth="0.8*"/>
- <colspec colnum="2" colwidth="0.5*"/>
- <colspec colnum="3" colwidth="0.5*"/>
- <colspec colnum="4" colwidth="2.2*"/>
- <thead>
- <row>
- <entry>Champ</entry>
- <entry>Type</entry>
- <entry>Longueur</entry>
- <entry>Description</entry>
- </row>
- </thead>
- <tbody>
- <row>
- <entry>pd_lsn</entry>
- <entry>XLogRecPtr</entry>
- <entry>8 octets</entry>
- <entry>LSN : octet suivant le dernier octet de l'enregistrement
- xlog pour la dernière modification de cette page</entry>
- </row>
- <row>
- <entry>pd_tli</entry>
- <entry>uint16</entry>
- <entry>2 octets</entry>
- <entry>TimeLineID de la dernière modification (seulement les 16 bits de
- poids faible)</entry>
- </row>
- <row>
- <entry>pd_flags</entry>
- <entry>uint16</entry>
- <entry>2 octets</entry>
- <entry>Bits d'état</entry>
- </row>
- <row>
- <entry>pd_lower</entry>
- <entry>LocationIndex</entry>
- <entry>2 octets</entry>
- <entry>Décalage jusqu'au début de l'espace libre</entry>
- </row>
- <row>
- <entry>pd_upper</entry>
- <entry>LocationIndex</entry>
- <entry>2 octets</entry>
- <entry>Décalage jusqu'à la fin de l'espace libre</entry>
- </row>
- <row>
- <entry>pd_special</entry>
- <entry>LocationIndex</entry>
- <entry>2 octets</entry>
- <entry>Décalage jusqu'au début de l'espace spécial</entry>
- </row>
- <row>
- <entry>pd_pagesize_version</entry>
- <entry>uint16</entry>
- <entry>2 octets</entry>
- <entry>Taille de la page et disposition de l'information du numéro de
- version</entry>
- </row>
- <row>
- <entry>pd_prune_xid</entry>
- <entry>TransactionId</entry>
- <entry>4 bytes</entry>
- <entry>Plus vieux XMAX non traité sur la page, ou zéro si aucun</entry>
- </row>
- </tbody>
- </tgroup>
- </table>
-
- <para>
- Tous les détails se trouvent dans
- <filename>src/include/storage/bufpage.h</filename>.
- </para>
-
- <para>
-
- Après l'en-tête de la page se trouvent les identificateurs d'élément
- (<type>ItemIdData</type>), chacun nécessitant quatre octets. Un identificateur
- d'élément contient un décalage d'octet vers le début d'un élément, sa
- longueur en octets, et quelques bits d'attributs qui affectent son
- interprétation. Les nouveaux identificateurs d'éléments sont alloués si
- nécessaire à partir du début de l'espace non alloué. Le nombre d'identificateurs
- d'éléments présents peut être déterminé en regardant
- <structfield>pd_lower</structfield>, qui est augmenté pour allouer un nouvel
- identificateur. Comme un identificateur d'élément n'est jamais déplacé tant qu'il
- n'est pas libéré, son index pourrait être utilisé sur une base à long terme
- pour référencer un élément, même quand l'élément lui-même est déplacé le long de
- la page pour compresser l'espace libre. En fait, chaque pointeur vers un
- élément (<type>ItemPointer</type>, aussi connu sous le nom de
- <type>CTID</type>), créé par <productname>PostgreSQL</productname> consiste
- en un numéro de page et l'index de l'identificateur d'élément.
-
- </para>
-
- <para>
-
- Les éléments eux-mêmes sont stockés dans l'espace alloué en marche arrière,
- à partir de la fin de l'espace non alloué. La structure exacte varie
- suivant le contenu de la table. Les tables et les séquences utilisent toutes
- les deux une structure nommée <type>HeapTupleHeaderData</type>, décrite
- ci-dessous.
-
- </para>
-
- <para>
-
- La section finale est la <quote>section spéciale</quote> qui pourrait
- contenir tout ce que les méthodes d'accès souhaitent stocker. Par exemple,
- les index b-tree stockent des liens vers les enfants gauche et droit de la
- page ainsi que quelques autres données sur la structure de l'index. Les
- tables ordinaires n'utilisent pas du tout de section spéciale (indiquée
- en configurant <structfield>pd_special</structfield> à la taille de la page).
-
- </para>
-
- <para>
-
- Toutes les lignes de la table sont structurées de la même façon. Il existe
- un en-tête à taille fixe (occupant 23 octets sur la plupart des machines),
- suivi par un bitmap NULL optionnel, un champ ID de l'objet optionnel et les
- données de l'utilisateur. L'en-tête est détaillé dans <xref
- linkend="heaptupleheaderdata-table"/>. Les données réelles de l'utilisateur
- (les colonnes de la ligne) commencent àu décalage indiqué par
- <structfield>t_hoff</structfield>, qui doit toujours être un multiple de la distance
- MAXALIGN pour la plateforme. Le bitmap NULL est seulement présent si le bit
- <firstterm>HEAP_HASNULL</firstterm> est initialisé dans
- <structfield>t_infomask</structfield>. S'il est présent, il commence juste
- après l'en-tête fixe et occupe suffisamment d'octets pour avoir un bit par colonne
- de données (c'est-à-dire <structfield>t_natts</structfield> bits ensemble). Dans cette
- liste de bits, un bit 1 indique une valeur non NULL, un bit 0 une valeur
- NULL. Quand le bitmap n'est pas présent, toutes les colonnes sont supposées
- non NULL. L'ID de l'objet est seulement présent si le bit
- <firstterm>HEAP_HASOID</firstterm> est initialisé dans
- <structfield>t_infomask</structfield>. S'il est présent, il apparaît juste
- avant la limite <structfield>t_hoff</structfield>. Tout ajout nécessaire pour faire
- de <structfield>t_hoff</structfield> un multiple de MAXALIGN apparaîtra entre le
- bitmap NULL et l'ID de l'objet. (Ceci nous assure en retour que l'ID de
- l'objet est convenablement aligné.)
-
- </para>
-
- <table tocentry="1" id="heaptupleheaderdata-table">
- <title>Disposition de HeapTupleHeaderData</title>
- <titleabbrev>Disposition de HeapTupleHeaderData</titleabbrev>
- <tgroup cols="4">
- <colspec colnum="1" colwidth="0.5*"/>
- <colspec colnum="2" colwidth="0.5*"/>
- <colspec colnum="3" colwidth="0.5*"/>
- <colspec colnum="4" colwidth="2.5*"/>
- <thead>
- <row>
- <entry>Champ</entry>
- <entry>Type</entry>
- <entry>Longueur</entry>
- <entry>Description</entry>
- </row>
- </thead>
- <tbody>
- <row>
- <entry>t_xmin</entry>
- <entry>TransactionId</entry>
- <entry>4 octets</entry>
- <entry>XID d'insertion</entry>
- </row>
- <row>
- <entry>t_xmax</entry>
- <entry>TransactionId</entry>
- <entry>4 octets</entry>
- <entry>XID de suppression</entry>
- </row>
- <row>
- <entry>t_cid</entry>
- <entry>CommandId</entry>
- <entry>4 octets</entry>
- <entry>CID d'insertion et de suppression (surcharge avec t_xvac)</entry>
- </row>
- <row>
- <entry>t_xvac</entry>
- <entry>TransactionId</entry>
- <entry>4 octets</entry>
- <entry>XID pour l'opération VACUUM déplaçant une version de ligne</entry>
- </row>
- <row>
- <entry>t_ctid</entry>
- <entry>ItemPointerData</entry>
- <entry>6 octets</entry>
- <entry>TID en cours pour cette version de ligne ou pour une version plus
- récente</entry>
- </row>
- <row>
- <entry>t_infomask2</entry>
- <entry>int16</entry>
- <entry>2 octets</entry>
- <entry>nombre d'attributs et quelques bits d'état</entry>
- </row>
- <row>
- <entry>t_infomask</entry>
- <entry>uint16</entry>
- <entry>2 octets</entry>
- <entry>différents bits d'options (flag bits)</entry>
- </row>
- <row>
- <entry>t_hoff</entry>
- <entry>uint8</entry>
- <entry>1 octet</entry>
- <entry>décalage vers les données utilisateur</entry>
- </row>
- </tbody>
- </tgroup>
- </table>
-
- <para>
- Tous les détails sont disponibles dans
- <filename>src/include/access/htup.h</filename>.
- </para>
-
- <para>
-
- Interpréter les données réelles peut seulement se faire avec des informations
- obtenues à partir d'autres tables, principalement
- <structname>pg_attribute</structname>. Les valeurs clés nécessaires pour
- identifier les emplacements des champs sont
- <structfield>attlen</structfield> et <structfield>attalign</structfield>.
- Il n'existe aucun moyen pour obtenir directement un attribut particulier,
- sauf quand il n'y a que des champs de largeur fixe et aucune colonne NULL.
- Tout ceci est emballé dans les fonctions
- <firstterm>heap_getattr</firstterm>, <firstterm>fastgetattr</firstterm>
- et <firstterm>heap_getsysattr</firstterm>.
- </para>
- <para>
-
- Pour lire les données, vous avez besoin d'examinez chaque attribut à son
- tour. Commencez par vérifier si le champ est NULL en fonction du bitmap NULL.
- S'il l'est, allez au suivant. Puis, assurez-vous que vous avez le bon
- alignement. Si le champ est un champ à taille fixe, alors tous les octets
- sont placés simplement. S'il s'agit d'un champ à taille variable
- (attlen = -1), alors c'est un peu plus compliqué. Tous les types de données
- à longueur variable partagent la même structure commune d'en-tête,
- <type>struct varlena</type>, qui inclut la longueur totale de la valeur stockée
- et quelques bits d'option. Suivant les options, les données pourraient être
- soit dans la table de base soit dans une table <acronym>TOAST</acronym> ;
- elles pourraient aussi être compressées (voir <xref
- linkend="storage-toast"/>).
-
- </para>
-</sect1>
-
-</chapter>
Copied: traduc/tags/tv840rc2/storage.xml (from rev 1353, traduc/trunk/postgresql/storage.xml)
===================================================================
--- traduc/tags/tv840rc2/storage.xml (rev 0)
+++ traduc/tags/tv840rc2/storage.xml 2009-06-27 10:41:54 UTC (rev 1355)
@@ -0,0 +1,868 @@
+<?xml version="1.0" encoding="ISO-8859-15"?>
+<!-- Dernière modification
+ le $Date$
+ par $Author$
+ révision $Revision$ -->
+
+<chapter id="storage">
+
+<title>Stockage physique de la base de données</title>
+
+<para>
+Ce chapitre fournit un aperçu du format de stockage physique utilisé par les
+bases de données <productname>PostgreSQL</productname>.
+</para>
+
+<sect1 id="storage-file-layout">
+
+<title>Emplacement des fichiers de la base de données</title>
+
+<para>
+Cette section décrit le format de stockage au niveau des fichiers et
+répertoires.
+</para>
+
+<para>
+Toutes les données nécessaires à un groupe de bases de données sont stockées
+dans le répertoire data du groupe, habituellement référencé en tant que
+<varname>PGDATA</varname> (d'après le nom de la variable d'environnement qui peut
+être utilisé pour le définir). Un emplacement courant pour <varname>PGDATA</varname>
+est <filename>/var/lib/pgsql/data</filename>. Plusieurs groupes, gérés par différentes
+instances du serveur, peuvent exister sur la même machine.
+</para>
+
+<para>
+Le répertoire <varname>PGDATA</varname> contient plusieurs sous-répertoires et
+fichiers de contrôle, comme indiqué dans le <xref linkend="pgdata-contents-table"/>.
+En plus de ces éléments requis, les fichiers
+de configuration du groupe, <filename>postgresql.conf</filename>,
+<filename>pg_hba.conf</filename> et <filename>pg_ident.conf</filename> sont
+traditionnellement stockés dans <varname>PGDATA</varname> (bien qu'il soit possible de
+les conserver ailleurs à partir de la version 8.0 de
+<productname>PostgreSQL</productname>).
+</para>
+
+<table tocentry="1" id="pgdata-contents-table">
+<title>Contenu de <varname>PGDATA</varname></title>
+<tgroup cols="2">
+<colspec colnum="1" colwidth="0.5*"/>
+<colspec colnum="2" colwidth="1.5*"/>
+<thead>
+<row>
+<entry>Élément</entry>
+<entry>Description</entry>
+</row>
+</thead>
+
+<tbody>
+
+<row>
+ <entry><filename>PG_VERSION</filename></entry>
+ <entry>Un fichier contenant le numéro de version majeur de
+ <productname>PostgreSQL</productname></entry>
+</row>
+
+<row>
+ <entry><filename>base</filename></entry>
+ <entry>Sous-répertoire contenant les sous-répertoires par base de
+ données</entry>
+</row>
+
+<row>
+ <entry><filename>global</filename></entry>
+ <entry>Sous-répertoire contenant les tables communes au groupe, telles que
+ <structname>pg_database</structname></entry>
+</row>
+
+<row>
+ <entry><filename>pg_clog</filename></entry>
+ <entry>Sous-répertoire contenant les données d'état de validation des
+ transactions</entry>
+</row>
+
+<row>
+ <entry><filename>pg_multixact</filename></entry>
+ <entry>Sous-répertoire contenant des données sur l'état des
+ multi-transactions (utilisé pour les verrous de lignes partagées)</entry>
+</row>
+
+<row>
+ <entry><filename>pg_stat_tmp</filename></entry>
+ <entry>Sous-répertoire contenant les fichiers temporaires pour le sous-système
+ des statistiques</entry>
+</row>
+
+<row>
+ <entry><filename>pg_subtrans</filename></entry>
+ <entry>Sous-répertoire contenant les données d'états des
+ sous-transaction</entry>
+</row>
+
+<row>
+ <entry><filename>pg_tblspc</filename></entry>
+ <entry>Sous-répertoire contenant les liens symboliques vers les espaces
+ logiques</entry>
+</row>
+
+<row>
+ <entry><filename>pg_twophase</filename></entry>
+ <entry>Sous-répertoire contenant les fichiers d'état pour les transactions
+ préparées</entry>
+</row>
+
+<row>
+ <entry><filename>pg_xlog</filename></entry>
+ <entry>Sous-répertoire contenant les fichiers WAL (Write Ahead Log)</entry>
+</row>
+
+<row>
+ <entry><filename>postmaster.opts</filename></entry>
+ <entry>Un fichier enregistrant les options en ligne de commande avec
+ lesquelles le serveur a été lancé la dernière fois</entry>
+</row>
+
+<row>
+ <entry><filename>postmaster.pid</filename></entry>
+ <entry>Un fichier verrou enregistrant le PID courant du serveur et l'identifiant
+ du segment de mémoire partagé (absent après l'arrêt du serveur)</entry>
+</row>
+
+</tbody>
+</tgroup>
+</table>
+
+<para>
+Pour chaque base de données dans le groupe, il existe un sous-répertoire dans
+<varname>PGDATA</varname><filename>/base</filename>, nommé d'après l'OID de la base de données
+dans <structname>pg_database</structname>. Ce sous-répertoire est l'emplacement par
+défaut pour les fichiers de la base de données; en particulier, ses
+catalogues système sont stockés ici.
+</para>
+
+<para>
+Chaque table et index sont stockés dans un fichier séparé, nommé d'après le
+numéro <firstterm>filenode</firstterm> de la table ou de l'index, lequel se
+trouve dans <structname>pg_class</structname>.<structfield>relfilenode</structfield>.
+En plus du fichier principal (appelé aussi « main fork »), chaque
+table et index a une <firstterm>carte des espaces libres</firstterm> (voir
+<xref linkend="storage-fsm"/>), qui stocke des informations sur les emplacements
+libres dans la relation. La carte des espace libre est stockée dans un fichier
+nommé par le numéro relfilenode à qui est ajouté le suffixe
+<literal>_fsm</literal>. Les tables ont aussi un fichier pour la <firstterm>carte de
+visibilité</firstterm>, de suffixe <literal>_vm</literal>, pour tracer les pages connues
+pour n'avoir aucune ligne morte.
+La carte de visibilité est décrite plus bas dans <xref linkend="storage-vm"/>.
+</para>
+
+<caution>
+<para>
+Notez que, bien que le filenode de la table correspond souvent à son OID,
+cela n'est <emphasis>pas</emphasis> nécessairement le cas; certaines
+opérations, comme <command>TRUNCATE</command>, <command>REINDEX</command>,
+<command>CLUSTER</command> et quelques formes d'<command>ALTER TABLE</command>, peuvent
+modifier le filenode tout en préservant l'OID. Évitez de supposer que filenode
+et OID sont identiques.
+</para>
+</caution>
+
+<para>
+Quand une table ou un index dépasse 1 Go, il est divisé en
+<firstterm>segments</firstterm> d'un Go. Le nom du fichier du premier
+segment est identique au filenode ; les segments suivants sont nommés
+filenode.1, filenode.2, etc. Cette disposition évite des problèmes sur les
+plateformes qui ont des limitations sur les tailles des fichiers.
+(Actuellement, 1 Go est la taille du segment par défaut. Cette taille est
+ajustable en utilisant l'option <option>--with-segsize</option> pour configure
+avant de construire <productname>PostgreSQL</productname>.)
+En principe, les fichiers de la carte des espaces libres et de la carte de
+visibilité pourraient aussi nécessiter plusieurs segments, bien qu'il y a
+peu de chance que cela arrive réellement.
+Le contenu des tables et des index est discuté plus
+en détails dans <xref linkend="storage-page-layout"/>.
+</para>
+
+<para>
+Une table contenant des colonnes avec des entrées potentiellement volumineuses
+aura une table <firstterm>TOAST</firstterm> associée, qui est
+utilisée pour le stockage de valeurs de champs trop importantes pour
+conserver des lignes adéquates.
+<structname>pg_class</structname>.<structfield>reltoastrelid</structfield> établit un lien entre
+une table et sa table <acronym>TOAST</acronym>, si elle existe. Voir <xref
+linkend="storage-toast"/> pour plus d'informations.
+</para>
+
+<para>
+Les tablespaces rendent ce scénario plus compliqués. Chaque espace
+logique défini par l'utilisateur contient un lien symbolique dans le répertoire
+<varname>PGDATA</varname><filename>/pg_tblspc</filename>, pointant vers le répertoire physique
+du tablespace (comme spécifié dans sa commande <command>CREATE
+TABLESPACE</command>). Le lien symbolique est nommé d'après l'OID du tablespace.
+À l'intérieur du répertoire du tablespace, il existe un sous-répertoire
+pour chacune des bases de données contenant des éléments dans ce tablespace. Ce
+sous-répertoire est nommé d'après l'OID de la base. Les tables de
+ce répertoire suivent le schéma de nommage des filenodes. Le tablespace
+<literal>pg_default</literal> n'est pas accédé via <filename>pg_tblspc</filename> mais
+correspond à <varname>PGDATA</varname><filename>/base</filename>. De façon similaire,
+le tablespace <literal>pg_global</literal> n'est pas accédé via
+<filename>pg_tblspc</filename> mais correspond à <varname>PGDATA</varname><filename>/global</filename>.
+</para>
+
+<para>
+Les fichiers temporaires (pour des opérations comme le tri de plus de données
+que ce que la mémoire peut contenir) sont créés à l'intérieur de <varname>PGDATA</varname><filename>/base/pgsql_tmp</filename>,
+ou dans un sous-répertoire <filename>pgsql_tmp</filename> du répertoire du
+tablespace si un tablespace autre que <literal>pg_default</literal> est
+indiqué pour eux. Le nom du fichier temporaire est de la forme
+<filename>pgsql_tmp<replaceable>PPP</replaceable>.<replaceable>NNN</replaceable></filename>,
+où <replaceable>PPP</replaceable> est le PID du serveur propriétaire et
+<replaceable>NNN</replaceable> distingue les différents fichiers temporaires de ce
+serveur.
+</para>
+
+</sect1>
+
+<sect1 id="storage-toast">
+
+<title>TOAST</title>
+
+ <indexterm>
+ <primary>TOAST</primary>
+ </indexterm>
+ <indexterm><primary>sliced bread</primary><see>TOAST</see></indexterm>
+
+<para>
+Cette section fournit un aperçu de <acronym>TOAST</acronym> (<foreignphrase>The
+Oversized-Attribute Storage Technique</foreignphrase>, la technique de
+stockage des attributs trop grands).
+</para>
+
+<para>
+Puisque <productname>PostgreSQL</productname> utilise une taille de page fixe
+(habituellement 8 Ko) et n'autorise pas qu'une ligne s'étende sur plusieurs
+pages. Du coup, il n'est pas possible de stocker de grandes valeurs directement
+dans les champs. Pour dépasser cette limitation, les valeurs de champ
+volumineuses sont compressées et/ou divisées en plusieurs lignes physiques. Ceci
+survient de façon transparente pour l'utilisateur, avec seulement un petit
+impact sur le code du serveur. Cette technique est connu sous l'acronyme
+affectueux de <acronym>TOAST</acronym> (ou <quote>the best thing since sliced
+bread</quote>).
+</para>
+
+<para>
+Seuls certains types de données supportent <acronym>TOAST</acronym> — il n'est
+pas nécessaire d'imposer cette surcharge sur les types de données qui ne
+produisent pas de gros volumes. Pour supporter
+<acronym>TOAST</acronym>, un type de données doit avoir une représentation
+(<firstterm>varlena</firstterm>) à longueur variable, dans laquelle les 32 premiers bits
+contiennent la longueur totale de la valeur en octets (ceci incluant la
+longueur elle-même). <acronym>TOAST</acronym> n'a aucune contrainte supplémentaire
+sur la représentation. Toutes les fonctions niveau C qui gèrent un type données
+supportant <acronym>TOAST</acronym> doivent faire attention à gérer les valeurs en
+entrée <acronym>TOAST</acronym>ées. (Ceci se fait normalement en appelant
+<function>PG_DETOAST_DATUM</function> avant de faire quoi que ce soit avec une valeur
+en entrée; mais dans certains cas, des approches plus efficaces sont possibles.)
+</para>
+
+<para>
+<acronym>TOAST</acronym> récupère deux bits du mot contenant la longueur
+d'un varlena (ceux de poids fort sur les machines big-endian, ceux de poids
+faible sur les machines little-endian), limitant du coup la taille logique
+de toute valeur d'un type de données <acronym>TOAST</acronym> à 1 Go
+(2<superscript>30</superscript> - 1 octets). Quand les deux bits sont à
+zéro, la valeur est une valeur non <acronym>TOAST</acronym>é du type de
+données et les bits restants dans le mot contenant la longueur indique
+la taille total du datum (incluant ce mot) en octets. Quand le bit de poids
+fort (ou de poids faible) est à un, la valeur a un en-tête de seulement
+un octet alors qu'un en-tête normal en fait quatre. Les bits restants
+donne la taille total du datum (incluant ce mot) en octets. Il reste un
+cas spécial : si les bits restants sont tous à zéro (ce qui est
+impossible étant donné que le mot indiquant la longueur est inclut dans
+la taille), la valeur est un pointeur vers une donnée stockée dans une table
+TOAST séparée (la taille d'un pointeur TOAST est indiquée dans le second
+octet du datum). Les valeurs dont l'en-tête fait un seul octet ne sont pas
+alignées sur une limite particulière. Enfin, quand le bit de poids fort
+(ou de poids faible) est supprimé mais que le bit adjacent vaut un, le
+contenu du datum est compressé et doit être décompresser avant utilisation.
+Dans ce cas, les bits restants du mot contenant la longueur indiquent la
+taille totale du datum compressé, pas celles des données au départ. Notez
+que la compression est aussi possible pour les données de la table TOAST
+mais l'en-tête varlena n'indique pas si c'est le cas — le contenu
+du pointeur TOAST le précise.
+</para>
+
+<para>
+Si une des colonnes d'une table est <acronym>TOAST</acronym>-able, la table disposera
+d'une table <acronym>TOAST</acronym> associé, dont l'OID est stockée dans l'entrée
+<structname>pg_class</structname>.<structfield>reltoastrelid</structfield> de la table. Les valeurs
+<acronym>TOAST</acronym>ées hors-ligne sont conservées dans la table <acronym>TOAST</acronym>
+comme décrit avec plus de détails ci-dessous.
+</para>
+
+<para>
+La technique de compression utilisée est un simple et rapide membre de la
+famille des techniques de compression LZ. Voir <filename>src/backend/utils/adt/pg_lzcompress.c</filename> pour les
+détails.
+</para>
+
+<para>
+Les valeurs hors-ligne sont divisées (après compression si nécessaire) en
+morceaux d'au plus <literal>TOAST_MAX_CHUNK_SIZE</literal> octets (par défaut,
+cette valeur est choisie pour que quatre morceaux de ligne tiennent sur une
+page, d'où les 2000 octets). Chaque morceau est stocké comme une ligne séparée dans la table
+<acronym>TOAST</acronym> de la table propriétaire. Chaque table <acronym>TOAST</acronym>
+contient les colonnes <structfield>chunk_id</structfield> (un OID identifiant la valeur
+<acronym>TOAST</acronym>ée particulière), <structfield>chunk_seq</structfield> (un numéro de
+séquence pour le morceau de la valeur) et <structfield>chunk_data</structfield> (la donnée
+réelle du morceau). Un index unique sur <structfield>chunk_id</structfield> et
+<structfield>chunk_seq</structfield> offre une récupération rapide des valeurs. Un
+pointeur datum représentant une valeur <acronym>TOAST</acronym>ée hors-ligne a par conséquent
+besoin de stocker l'OID de la table <acronym>TOAST</acronym> dans laquelle chercher
+et l'OID de la valeur spécifique (son <structfield>chunk_id</structfield>). Par commodité,
+les pointeurs datums stockent aussi la taille logique du datum (taille
+de la donnée originale non compressée) et la taille stockée réelle (différente
+si la compression a été appliquée). À partir des octets d'en-tête varlena,
+la taille totale d'un pointeur datum <acronym>TOAST</acronym> est par conséquent de 18 octets
+quelque soit la taille réelle de la valeur représentée.
+</para>
+
+<para>
+Le code <acronym>TOAST</acronym> est déclenché seulement quand une valeur de ligne
+à stocker dans une table est plus grande que <symbol>TOAST_TUPLE_THRESHOLD</symbol> octets (habituellement
+2 Ko). Le code <acronym>TOAST</acronym> compressera et/ou déplacera les valeurs
+de champ hors la ligne jusqu'à ce que la valeur de la ligne soit plus petite que
+<symbol>TOAST_TUPLE_TARGET</symbol> octets (habituellement là-aussi
+2 Ko) ou que plus aucun gain ne puisse être réalisé.
+Lors d'une opération UPDATE, les valeurs des champs non modifiées sont habituellement
+préservées telles quelles ; donc un UPDATE sur une ligne avec des valeurs hors
+ligne n'induit pas de coûts à cause de <acronym>TOAST</acronym> si aucune des valeurs
+hors-ligne n'est modifiée.
+</para>
+
+<para>
+Le code <acronym>TOAST</acronym> connaît quatre stratégies différentes pour stocker
+les colonnes <acronym>TOAST</acronym>-ables :
+
+ <itemizedlist>
+ <listitem>
+ <para>
+ <literal>PLAIN</literal> empêche soit la compression soit le stockage
+ hors-ligne ; de plus, il désactive l'utilisation d'en-tête sur
+ un octet pour les types varlena. Ceci est la seule stratégie possible
+ pour les colonnes des types de données non
+ <acronym>TOAST</acronym>-ables.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>EXTENDED</literal> permet à la fois la compression et le
+ stockage hors-ligne. Ceci est la valeur par défaut de la plupart des
+ types de données <acronym>TOAST</acronym>-ables. La compression sera tentée en
+ premier, ensuite le stockage hors-ligne si la ligne est toujours trop
+ grande.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>EXTERNAL</literal> autorise le stockage hors-ligne mais pas la
+ compression. L'utilisation d'<literal>EXTERNAL</literal> rendra plus rapides les
+ opérations sur des sous-chaînes d'importantes colonnes de type
+ <type>text</type> et <type>bytea</type> (au dépens d'un
+ espace de stockage accrus) car ces opérations sont optimisées pour
+ récupérer seulement les parties requises de la valeur hors-ligne
+ lorsqu'elle n'est pas compressée.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>MAIN</literal> autorise la compression mais pas le stockage
+ hors-ligne. (En réalité le stockage hors-ligne sera toujours réalisé
+ pour de telles colonnes mais seulement en dernier ressort s'il n'existe
+ aucune autre solution pour diminuer suffisamment la taille de la ligne.)
+ </para>
+ </listitem>
+ </itemizedlist>
+
+Chaque type de données <acronym>TOAST</acronym>-able spécifie une stratégie par défaut
+pour les colonnes de ce type de donnée, mais la stratégie pour une colonne d'une table
+donnée peut être modifiée avec <command>ALTER TABLE SET STORAGE</command>.
+</para>
+
+<para>
+Cette combinaison a de nombreux avantages comparés à une approche plus directe
+comme autoriser le stockage des valeurs de lignes sur plusieurs pages. En
+supposant que les requêtes sont habituellement qualifiées par comparaison avec
+des valeurs de clé relativement petites, la grosse partie du travail de
+l'exécuteur sera réalisée en utilisant l'entrée principale de la ligne. Les
+grandes valeurs des attributs <acronym>TOAST</acronym>és seront seulement récupérées
+(si elles sont sélectionnées) au moment où l'ensemble de résultats est
+envoyé au client. Ainsi, la table principale est bien plus petite
+et un plus grand nombre de ses lignes tiennent dans le cache du tampon partagé,
+ce qui ne serait pas le cas sans aucun stockage hors-ligne.
+Le tri l'utilise aussi, et les tris seront plus souvent réalisés entièrement
+en mémoire. Un petit test a montré qu'une table contenant des pages HTML
+typiques ainsi que leurs URL étaient stockées en à peu près la moitié de la
+taille des données brutes en incluant la table <acronym>TOAST</acronym> et que la
+table principale contenait moins de 10 % de la totalité des données (les
+URL et quelques petites pages HTML). Il n'y avait pas de différence à l'exécution
+en comparaison avec une table non <acronym>TOAST</acronym>ée, dans laquelle toutes les
+pages HTLM avaient été coupées à 7 Ko pour tenir.
+</para>
+
+</sect1>
+
+<sect1 id="storage-fsm">
+
+<title>Carte des espaces libres</title>
+
+<indexterm>
+ <primary>Free Space Map</primary>
+</indexterm>
+<indexterm><primary>FSM</primary><see>Free Space Map</see></indexterm>
+
+<para>
+Chaque table et index, en dehors des index hash, a une carte des espaces libres
+(appelée aussi <acronym>FSM</acronym>, acronyme de <foreignphrase>Free Space
+Map</foreignphrase>) pour conserver le trace des emplacements disponibles dans
+la relation. Elle est stockée dans un fichier séparé du fichier des données. Le
+nom de fichier est le numéro relfilenode suivi du suffixe
+<literal>_fsm</literal>. Par exemple, si le relfilenode d'une relation est
+12345, la FSM est stockée dans un fichier appelé
+<filename>12345_fsm</filename>, dans même répertoire que celui utilisé pour le
+fichier des données.
+</para>
+
+<para>
+La carte des espaces libres est organisée comme un arbre de pages
+<acronym>FSM</acronym>. Les pages <acronym>FSM</acronym> de niveau bas stockent
+l'espace libre disponible dans chaque page de la relation. Les niveaux
+suppérieurs agrégent l'information des niveaux bas.
+</para>
+
+<para>
+À l'intérieur de chaque page <acronym>FSM</acronym> se trouve un arbre binaire
+stocké dans un tableau avec un octet par nœud. Chaque nœud final
+représente une page de la relation, ou une page FSM de niveau bas. Dans chaque
+nœud non final, la valeur la plus haute des valeurs enfants est stockée.
+Du coup, la valeur maximum de tous les nœuds se trouve à la racine.
+</para>
+
+<para>
+Voir <filename>src/backend/storage/freespace/README</filename> pour plus de
+détails sur la façon dont la <acronym>FSM</acronym> est structurée, et comment
+elle est mise à jour et recherchée. Le module contrib
+<filename>contrib/pg_freespacemap</filename> peut être utilisé pour examiner
+l'information stockée dans les cartes d'espace libre (voir <xref
+linkend="pgfreespacemap"/>).
+</para>
+
+</sect1>
+
+<sect1 id="storage-vm">
+
+<title>Carte de visibilité</title>
+
+<indexterm>
+ <primary>Carte de visibilité</primary>
+</indexterm>
+<indexterm><primary>VM</primary><see>Carte de visibilité</see></indexterm>
+
+<para>
+Chaque relation a une carte de visibilité (<acronym>VM</acronym> acronyme de
+<foreignphrase>Visibility Map</foreignphrase>) pour garder trace des pages
+contenant seulement des lignes connues pour être visibles par toutes les
+transactions actives. Elle est stockée en dehors du fichier de données dans
+un fichier séparé nommé suivant le numéro relfilenode de la relation, auquel
+est ajouté le suffixe <literal>_vm</literal>. Par exemple, si le relfilenode
+de la relation est 12345, la VM est stockée dans un fichier appelé
+<filename>12345_vm</filename>, dans le même répertoire que celui du fichier
+de données. Notez que les index n'ont pas de VM.
+</para>
+
+<para>
+La carte de visibilité enregistre un bit par page. Un bit à 1 signifie
+que toutes les lignes de la page sont visibles par toutes les transactions.
+Cela signifie que le page ne contient pas de lignes nécessitant un VACUUM ;
+dans le futur, cela pourra aussi être utilisé pour éviter de visiter la page
+lors de vérifications de visibilité. Chaque fois qu'un bit est à 1, la condition
+est vraie à coup sûr. Par contre, dans le cas contraire, la condition peut être
+vraie comme fausse.
+</para>
+
+</sect1>
+
+<sect1 id="storage-page-layout">
+
+<title>Emplacement des pages de la base de données</title>
+
+<para>
+Cette section fournit un aperçu du format des pages utilisées par les tables et
+index de <productname>PostgreSQL</productname>.<footnote>
+ <para>
+ En réalité, les méthodes d'accès par index n'ont pas besoin d'utiliser ce
+ format de page. Toutes les méthodes d'indexage existantes utilisent ce
+ format de base mais les données conservées dans les métapages des index
+ ne suivent habituellement pas les règles d'emplacement des éléments.
+ </para>
+</footnote>
+Les séquences et les tables <acronym>TOAST</acronym> tables sont formatées comme des
+tables standards.
+</para>
+
+<para>
+Dans l'explication qui suit, un <firstterm>octet</firstterm> contient huit
+bits. De plus, le terme <firstterm>élément</firstterm> fait référence à une
+valeur de données individuelle qui est stockée dans une page. Dans une table,
+un élément est une ligne ; dans un index, un élément est une entrée
+d'index.
+</para>
+
+<para>
+Chaque table et index est stocké comme un tableau de <firstterm>pages</firstterm> d'une
+taille fixe (habituellement 8 Ko, bien qu'une taille de page différente
+peut être sélectionnée lors de la compilation du serveur). Dans une table,
+toutes les pages sont logiquement équivalentes pour qu'un élément (ligne)
+particulier puisse être stocké dans n'importe quelle page. Dans les index, la
+première page est généralement réservée comme <firstterm>métapage</firstterm> contenant
+des informations de contrôle, et il peut exister différents types de pages à
+l'intérieur de l'index, suivant la méthode d'accès à l'index. Les tables ont
+aussi une carte de visibilité dans un fichier de suffixe <literal>_vm</literal>,
+pour tracer les pages dont on sait qu'elles ne contiennent pas de lignes mortes
+et qui n'ont pas du coup besoin de VACUUM.
+</para>
+
+<para>
+<xref linkend="page-table"/> affiche le contenu complet d'une page. Il existe
+cinq parties pour chaque page.
+</para>
+
+<table tocentry="1" id="page-table">
+<title>Disposition générale d'une page</title>
+<titleabbrev>Disposition d'une page</titleabbrev>
+<tgroup cols="2">
+<colspec colnum="1" colwidth="0.5*"/>
+<colspec colnum="2" colwidth="1.5*"/>
+<thead>
+<row>
+<entry>Élément</entry>
+<entry>Description</entry>
+</row>
+</thead>
+
+<tbody>
+
+<row>
+ <entry>PageHeaderData</entry>
+ <entry>Longueur de 24 octets. Contient des informations générales sur la page y compris
+ des pointeurs sur les espaces libres.</entry>
+</row>
+
+<row>
+ <entry>ItemIdData</entry>
+ <entry>Tableau de paires (décalage,longueur) pointant sur les éléments réels.
+ Quatre octets par élément.</entry>
+</row>
+
+<row>
+ <entry>Free space</entry>
+ <entry>L'espace non alloué. Les pointeurs de nouveaux éléments sont alloués
+ à partir du début de cette région, les nouveaux éléments à partir de la
+ fin.</entry>
+</row>
+
+<row>
+ <entry>Items</entry>
+ <entry>Les éléments eux-mêmes.</entry>
+</row>
+
+<row>
+ <entry>Special space</entry>
+ <entry>Données spécifiques des méthodes d'accès aux index. Différentes
+ méthodes stockent différentes données. Vide pour les tables
+ ordinaires.</entry>
+</row>
+
+</tbody>
+</tgroup>
+</table>
+
+ <para>
+
+ Les 24 premiers octets de chaque page consistent en un en-tête de page
+ (PageHeaderData). Son format est détaillé dans <xref
+ linkend="pageheaderdata-table"/>. Les deux premiers champs traquent l'entrée
+ WAL la plus récente relative à cette page. Ensuite se trouve un champ de
+ deux octets contenant des drapeaux. Ils sont suivis par trois
+ champs d'entiers sur deux octets (<structfield>pd_lower</structfield>,
+ <structfield>pd_upper</structfield> et
+ <structfield>pd_special</structfield>). Ils contiennent des décalages
+ d'octets à partir du début de la page jusqu'au début de l'espace non alloué,
+ jusqu'à la fin de l'espace non alloué, et jusqu'au début de l'espace spécial.
+ Les deux octets suivants de l'en-tête de page,
+ <structfield>pd_pagesize_version</structfield>, stockent à la fois la taille
+ de la page et un indicateur de versoin. À partir de la version 8.3 de
+ <productname>PostgreSQL</productname>, le numéro de version est 4 ;
+ <productname>PostgreSQL</productname> 8.1 et 8.2 ont utilisé le numéro de version 3 ;
+ <productname>PostgreSQL</productname> 8.0 a utilisé le numéro de version 2 ;
+ <productname>PostgreSQL</productname> 7.3 et 7.4 ont utilisé le numéro de
+ version 1 ; les versions précédentes utilisaient le numéro de version 0.
+ (La disposition fondamentale de la page et le format de l'en-tête n'ont pas changé
+ dans la plupart de ces versions mais la disposition de l'en-tête des lignes de tête a
+ changé.) La taille de la page est seulement présente comme vérification
+ croisée ; il n'existe pas de support pour avoir plus d'une taille de
+ page dans une installation.
+ Le dernier champ est une aide indiquant si traiter la page serait
+ profitable : il garde l'information sur le plus vieux XMAX non traité
+ de la page.
+ </para>
+
+ <table tocentry="1" id="pageheaderdata-table">
+ <title>Disposition de PageHeaderData</title>
+ <titleabbrev>Disposition de PageHeaderData</titleabbrev>
+ <tgroup cols="4">
+ <colspec colnum="1" colwidth="0.8*"/>
+ <colspec colnum="2" colwidth="0.5*"/>
+ <colspec colnum="3" colwidth="0.5*"/>
+ <colspec colnum="4" colwidth="2.2*"/>
+ <thead>
+ <row>
+ <entry>Champ</entry>
+ <entry>Type</entry>
+ <entry>Longueur</entry>
+ <entry>Description</entry>
+ </row>
+ </thead>
+ <tbody>
+ <row>
+ <entry>pd_lsn</entry>
+ <entry>XLogRecPtr</entry>
+ <entry>8 octets</entry>
+ <entry>LSN : octet suivant le dernier octet de l'enregistrement
+ xlog pour la dernière modification de cette page</entry>
+ </row>
+ <row>
+ <entry>pd_tli</entry>
+ <entry>uint16</entry>
+ <entry>2 octets</entry>
+ <entry>TimeLineID de la dernière modification (seulement les 16 bits de
+ poids faible)</entry>
+ </row>
+ <row>
+ <entry>pd_flags</entry>
+ <entry>uint16</entry>
+ <entry>2 octets</entry>
+ <entry>Bits d'état</entry>
+ </row>
+ <row>
+ <entry>pd_lower</entry>
+ <entry>LocationIndex</entry>
+ <entry>2 octets</entry>
+ <entry>Décalage jusqu'au début de l'espace libre</entry>
+ </row>
+ <row>
+ <entry>pd_upper</entry>
+ <entry>LocationIndex</entry>
+ <entry>2 octets</entry>
+ <entry>Décalage jusqu'à la fin de l'espace libre</entry>
+ </row>
+ <row>
+ <entry>pd_special</entry>
+ <entry>LocationIndex</entry>
+ <entry>2 octets</entry>
+ <entry>Décalage jusqu'au début de l'espace spécial</entry>
+ </row>
+ <row>
+ <entry>pd_pagesize_version</entry>
+ <entry>uint16</entry>
+ <entry>2 octets</entry>
+ <entry>Taille de la page et disposition de l'information du numéro de
+ version</entry>
+ </row>
+ <row>
+ <entry>pd_prune_xid</entry>
+ <entry>TransactionId</entry>
+ <entry>4 bytes</entry>
+ <entry>Plus vieux XMAX non traité sur la page, ou zéro si aucun</entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+
+ <para>
+ Tous les détails se trouvent dans
+ <filename>src/include/storage/bufpage.h</filename>.
+ </para>
+
+ <para>
+
+ Après l'en-tête de la page se trouvent les identificateurs d'élément
+ (<type>ItemIdData</type>), chacun nécessitant quatre octets. Un identificateur
+ d'élément contient un décalage d'octet vers le début d'un élément, sa
+ longueur en octets, et quelques bits d'attributs qui affectent son
+ interprétation. Les nouveaux identificateurs d'éléments sont alloués si
+ nécessaire à partir du début de l'espace non alloué. Le nombre d'identificateurs
+ d'éléments présents peut être déterminé en regardant
+ <structfield>pd_lower</structfield>, qui est augmenté pour allouer un nouvel
+ identificateur. Comme un identificateur d'élément n'est jamais déplacé tant qu'il
+ n'est pas libéré, son index pourrait être utilisé sur une base à long terme
+ pour référencer un élément, même quand l'élément lui-même est déplacé le long de
+ la page pour compresser l'espace libre. En fait, chaque pointeur vers un
+ élément (<type>ItemPointer</type>, aussi connu sous le nom de
+ <type>CTID</type>), créé par <productname>PostgreSQL</productname> consiste
+ en un numéro de page et l'index de l'identificateur d'élément.
+
+ </para>
+
+ <para>
+
+ Les éléments eux-mêmes sont stockés dans l'espace alloué en marche arrière,
+ à partir de la fin de l'espace non alloué. La structure exacte varie
+ suivant le contenu de la table. Les tables et les séquences utilisent toutes
+ les deux une structure nommée <type>HeapTupleHeaderData</type>, décrite
+ ci-dessous.
+
+ </para>
+
+ <para>
+
+ La section finale est la <quote>section spéciale</quote> qui pourrait
+ contenir tout ce que les méthodes d'accès souhaitent stocker. Par exemple,
+ les index b-tree stockent des liens vers les enfants gauche et droit de la
+ page ainsi que quelques autres données sur la structure de l'index. Les
+ tables ordinaires n'utilisent pas du tout de section spéciale (indiquée
+ en configurant <structfield>pd_special</structfield> à la taille de la page).
+
+ </para>
+
+ <para>
+
+ Toutes les lignes de la table sont structurées de la même façon. Il existe
+ un en-tête à taille fixe (occupant 23 octets sur la plupart des machines),
+ suivi par un bitmap NULL optionnel, un champ ID de l'objet optionnel et les
+ données de l'utilisateur. L'en-tête est détaillé dans <xref
+ linkend="heaptupleheaderdata-table"/>. Les données réelles de l'utilisateur
+ (les colonnes de la ligne) commencent àu décalage indiqué par
+ <structfield>t_hoff</structfield>, qui doit toujours être un multiple de la distance
+ MAXALIGN pour la plateforme. Le bitmap NULL est seulement présent si le bit
+ <firstterm>HEAP_HASNULL</firstterm> est initialisé dans
+ <structfield>t_infomask</structfield>. S'il est présent, il commence juste
+ après l'en-tête fixe et occupe suffisamment d'octets pour avoir un bit par colonne
+ de données (c'est-à-dire <structfield>t_natts</structfield> bits ensemble). Dans cette
+ liste de bits, un bit 1 indique une valeur non NULL, un bit 0 une valeur
+ NULL. Quand le bitmap n'est pas présent, toutes les colonnes sont supposées
+ non NULL. L'ID de l'objet est seulement présent si le bit
+ <firstterm>HEAP_HASOID</firstterm> est initialisé dans
+ <structfield>t_infomask</structfield>. S'il est présent, il apparaît juste
+ avant la limite <structfield>t_hoff</structfield>. Tout ajout nécessaire pour faire
+ de <structfield>t_hoff</structfield> un multiple de MAXALIGN apparaîtra entre le
+ bitmap NULL et l'ID de l'objet. (Ceci nous assure en retour que l'ID de
+ l'objet est convenablement aligné.)
+
+ </para>
+
+ <table tocentry="1" id="heaptupleheaderdata-table">
+ <title>Disposition de HeapTupleHeaderData</title>
+ <titleabbrev>Disposition de HeapTupleHeaderData</titleabbrev>
+ <tgroup cols="4">
+ <colspec colnum="1" colwidth="0.5*"/>
+ <colspec colnum="2" colwidth="0.5*"/>
+ <colspec colnum="3" colwidth="0.5*"/>
+ <colspec colnum="4" colwidth="2.5*"/>
+ <thead>
+ <row>
+ <entry>Champ</entry>
+ <entry>Type</entry>
+ <entry>Longueur</entry>
+ <entry>Description</entry>
+ </row>
+ </thead>
+ <tbody>
+ <row>
+ <entry>t_xmin</entry>
+ <entry>TransactionId</entry>
+ <entry>4 octets</entry>
+ <entry>XID d'insertion</entry>
+ </row>
+ <row>
+ <entry>t_xmax</entry>
+ <entry>TransactionId</entry>
+ <entry>4 octets</entry>
+ <entry>XID de suppression</entry>
+ </row>
+ <row>
+ <entry>t_cid</entry>
+ <entry>CommandId</entry>
+ <entry>4 octets</entry>
+ <entry>CID d'insertion et de suppression (surcharge avec t_xvac)</entry>
+ </row>
+ <row>
+ <entry>t_xvac</entry>
+ <entry>TransactionId</entry>
+ <entry>4 octets</entry>
+ <entry>XID pour l'opération VACUUM déplaçant une version de ligne</entry>
+ </row>
+ <row>
+ <entry>t_ctid</entry>
+ <entry>ItemPointerData</entry>
+ <entry>6 octets</entry>
+ <entry>TID en cours pour cette version de ligne ou pour une version plus
+ récente</entry>
+ </row>
+ <row>
+ <entry>t_infomask2</entry>
+ <entry>int16</entry>
+ <entry>2 octets</entry>
+ <entry>nombre d'attributs et quelques bits d'état</entry>
+ </row>
+ <row>
+ <entry>t_infomask</entry>
+ <entry>uint16</entry>
+ <entry>2 octets</entry>
+ <entry>différents bits d'options (flag bits)</entry>
+ </row>
+ <row>
+ <entry>t_hoff</entry>
+ <entry>uint8</entry>
+ <entry>1 octet</entry>
+ <entry>décalage vers les données utilisateur</entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+
+ <para>
+ Tous les détails sont disponibles dans
+ <filename>src/include/access/htup.h</filename>.
+ </para>
+
+ <para>
+
+ Interpréter les données réelles peut seulement se faire avec des informations
+ obtenues à partir d'autres tables, principalement
+ <structname>pg_attribute</structname>. Les valeurs clés nécessaires pour
+ identifier les emplacements des champs sont
+ <structfield>attlen</structfield> et <structfield>attalign</structfield>.
+ Il n'existe aucun moyen pour obtenir directement un attribut particulier,
+ sauf quand il n'y a que des champs de largeur fixe et aucune colonne NULL.
+ Tout ceci est emballé dans les fonctions
+ <firstterm>heap_getattr</firstterm>, <firstterm>fastgetattr</firstterm>
+ et <firstterm>heap_getsysattr</firstterm>.
+ </para>
+ <para>
+
+ Pour lire les données, vous avez besoin d'examinez chaque attribut à son
+ tour. Commencez par vérifier si le champ est NULL en fonction du bitmap NULL.
+ S'il l'est, allez au suivant. Puis, assurez-vous que vous avez le bon
+ alignement. Si le champ est un champ à taille fixe, alors tous les octets
+ sont placés simplement. S'il s'agit d'un champ à taille variable
+ (attlen = -1), alors c'est un peu plus compliqué. Tous les types de données
+ à longueur variable partagent la même structure commune d'en-tête,
+ <type>struct varlena</type>, qui inclut la longueur totale de la valeur stockée
+ et quelques bits d'option. Suivant les options, les données pourraient être
+ soit dans la table de base soit dans une table <acronym>TOAST</acronym> ;
+ elles pourraient aussi être compressées (voir <xref
+ linkend="storage-toast"/>).
+
+ </para>
+</sect1>
+
+</chapter>
Plus d'informations sur la liste de diffusion Trad