web-dev-qa-db-fra.com

PostgreSQL, tableaux entier, index pour l'égalité

J'ai une énorme liste de tableaux entier (300 000 000 enregistrements) stockés dans Postgres 9,2 dB. Je veux rechercher efficacement ces enregistrements pour une correspondance exacte (égalité seulement). J'ai entendu parler du module intarray et des index de gis-gin correspondants. Je voudrais poser les questions suivantes:

  • Est-ce que PostgreSQL utilise une fonction de hachage pour vérifier l'égalité des tableaux entier ou effectuer une algorithme de force brute comparant un par un les éléments du tableau?
  • Si PostgreSQL utilise une fonction de hachage, existe-t-il du code de fonction PostgreSQL pour obtenir le résultat de la fonction Hash pour un tableau particulier?
  • Quel index sera le mieux pour une telle tâche? B-Tree ou les index gis-gin fournis par le module InTurray? L'ensemble de données sera statique, c'est-à-dire une fois que tous les enregistrements sont insérés, il n'y aura plus d'insertion. Ainsi, le temps d'indexation de l'indexation de la construction n'est pas important pour moi.
6
Alexandros

1) Comme vous l'avez déjà découvert, vous ne pouvez pas utiliser B-Tree car la taille de l'index est plus grande que la taille de la page.

2) donné:

En règle générale, un indice de gin est plus rapide de rechercher qu'un indice de gist, mais plus lentement à construire ou à mettre à jour; Donc, Gin est mieux adapté aux données statiques et gist pour des données souvent mises à jour.

Vous devriez utiliser Gin. Et non, Gin n'utilise pas les fonctions de hachage, ni un algorithme de force brute. C'est un indice inverse:

Un index GIN stocke un ensemble de paires (touches, de liste), où une liste d'envoi est un ensemble d'identifiants de lignes dans lesquels la clé se produit. Le même identifiant de ligne peut apparaître dans plusieurs listes d'affichage, car un élément peut contenir plus d'une clé. Chaque valeur de clé n'est stockée qu'une seule fois, donc un indice de gin est très compact pour les cas où la même clé apparaît plusieurs fois.

En interne, un indice de gin contient un indice B-Tree sur des touches construites, où chaque clé est un élément d'un ou plusieurs éléments indexés (un membre d'une matrice, par exemple))

2
Leo

Q: PostgreSQL utilise une fonction de hachage pour vérifier l'égalité des tableaux entier ou effectuer une algorithme de force brute comparant un seul-un-un des éléments de la matrice ?

Pas selon fonctions de tableau et opérateurs dans le document DOC:

Comparaisons de tableau Comparez le contenu de la matrice Elément par élément, à l'aide de la fonction de comparaison B-Tree par défaut pour le type de données d'élément.

Aucune mention de hachage.

intarray fournit d'autres opérateurs mais ne remplace pas l'opérateur d'égalité entre int[]. La fonction la plus proche _ int_seame () qu'elle expose est sémantiquement différente (l'ordre des éléments n'a pas d'importance) et est implémenté comme tri de tri + comparaison séquentielle, pas de hachage.


Heureusement, la mise en œuvre de la recherche basée sur HASH rapide au niveau SQL n'est pas difficile, et dans votre cas (grandes tableaux, aucune mise à jour, correspondance exacte), il peut même être la méthode la plus efficace.

Pas:

1) Choisissez une fonction de hachage. Je suggérerais md5 Sur la représentation du texte de la matrice:

create function arr_hash(int[]) returns bytea as
$$ select digest($1::text, 'md5');$$
language sql immutable;

La fonction digest(text,text) fait partie du pgcrypto Extension. Par rapport à md5 Il présente l'avantage de produire des binaires (16 octets) au lieu d'hexadécimal (32 octets) pour un index plus maigre.

2) Créer un indice fonctionnel:

create index index_name on table_name(arr_hash(col_name));

Ce sera plusieurs ordres de grandeur plus rapidement qu'un indice de gin pour le type de jeu de données que vous avez (en fait, je m'inquiéterais de la création de l'indice de gin prenant un temps vraiment déraisonnable, mais essayez-le).

3) Utilisez-le comme ceci:

select 1 from table_name
 where arr_hash(col_name)=arr_hash('{10,20,30,...lot of values}'::int[])
 and   col_name='{10,20,30,...lot of values}'::int[];
6
Daniel Vérité