2012-08-03 3 views
13

Disons que nous avons une table avec 6 millions d'enregistrements. Il y a 16 colonnes entières et quelques colonnes de texte. C'est une table en lecture seule, donc chaque colonne entière a un index. Chaque enregistrement avoisine 50-60 octets.Postgresql - performance de l'utilisation de tableau dans une grande base de données

Le nom de la table est "Item"
Le serveur est: 12 Go de RAM, 1,5 To de SATA, 4 CORES. Tous les serveurs pour postgres.
Il y a beaucoup plus de tables dans cette base de données afin que RAM ne couvre pas toutes les bases de données.

Je souhaite ajouter à la table "Item" une colonne "a_elements" (type tableau de grands entiers) Chaque enregistrement ne devrait pas contenir plus de 50-60 éléments dans cette colonne.

Après que je voudrais créer un index GIN sur cette colonne et requête typique devrait ressembler à ceci:

select * from item where ...... and '{5}' <@ a_elements; 

Je possède également un second, option plus classique.

Ne pas ajouter a_elements colonne à l'élément de table, mais créer des éléments de table avec deux colonnes:

  • id_item
  • id_element

Ce tableau aurait environ 200 millions dossiers.

Je suis capable de faire du partitionnement sur ces tables afin que le nombre d'enregistrements soit réduit à 20 mln dans les éléments de table et 500 K dans l'élément de table.

La deuxième requête d'option ressemble à ceci:

select item.* 
from item 
    left join elements on (item.id_item=elements.id_item) 
where .... 
and 5 = elements.id_element 

Je me demande quelle option serait mieux au point de vue de la performance. Postgres peut-il utiliser plusieurs index différents avec l'index GIN (option 1) dans une seule requête?

Je dois prendre une bonne décision car l'importation de ces données me prendra 20 jours.

+1

Salut! Et quelle est votre décision finale? J'ai presque la même situation. –

Répondre

10

Je pense que vous devriez utiliser une table elements:

  • Postgres serait en mesure d'utiliser les statistiques pour prédire le nombre de lignes correspondent avant d'exécuter la requête, il serait donc en mesure d'utiliser le meilleur plan de requête (c'est plus important si vos données ne sont pas distribuées uniformément); Vous pouvez localiser les données de requête en utilisant CLUSTER elements USING elements_id_element_idx;

  • Lorsque Postgres 9.2 serait libéré alors vous seriez en mesure de profiter des analyses d'index seulement;

Mais je l'ai fait quelques tests pour 10M éléments:

create table elements (id_item bigint, id_element bigint); 
insert into elements 
    select (random()*524288)::int, (random()*32768)::int 
    from generate_series(1,10000000); 

\timing 
create index elements_id_item on elements(id_item); 
Time: 15470,685 ms 
create index elements_id_element on elements(id_element); 
Time: 15121,090 ms 

select relation, pg_size_pretty(pg_relation_size(relation)) 
    from (
    select unnest(array['elements','elements_id_item', 'elements_id_element']) 
     as relation 
) as _; 
     relation  | pg_size_pretty 
---------------------+---------------- 
elements   | 422 MB 
elements_id_item | 214 MB 
elements_id_element | 214 MB 



create table arrays (id_item bigint, a_elements bigint[]); 
insert into arrays select array_agg(id_element) from elements group by id_item; 

create index arrays_a_elements_idx on arrays using gin (a_elements); 
Time: 22102,700 ms 

select relation, pg_size_pretty(pg_relation_size(relation)) 
    from (
    select unnest(array['arrays','arrays_a_elements_idx']) as relation 
) as _; 
     relation  | pg_size_pretty 
-----------------------+---------------- 
arrays    | 108 MB 
arrays_a_elements_idx | 73 MB 

Ainsi, dans les autres tableaux de main sont plus petits et ont l'indice plus petit. Je ferais quelques tests d'éléments 200M avant de prendre une décision.

Questions connexes