La fin du bannissement ?
Les Hash Index existent depuis très longtemps dans PostgreSQL mais leur usage était découragé pour plusieurs raisons. Dabord parce quil nétait pas évident quils permettaient dobtenir de meilleures performances que les index B-Tree, tout en étant plus lourds que ces derniers. Ensuite et surtout parce quils nétaient pas journalisés. Il fallait donc les reconstruire après un crash et ils étaient incompatibles avec les hot standby par exemple.
La restriction sur les performances a disparu de la documentation en 8.4. La restriction sur la journalisation a été levée en version 10. Les Hash Index présentent-ils vraiment un avantage dans les cas où ils sont théoriquement supérieurs aux B-Tree ? Il faut dabord déterminer un cas dutilisation. Pour cela nous allons nous appuyer sur le livre de Guillaume Lelarge "Architecture et notions avancées" dans lequel il écrit que les Hash Index reposent sur un principe simple. Plutôt que dindexer la valeur de la colonne, cest un entier correspondant à la valeur de hachage de cette colonne qui est indexé. Quel intérêt ? Tester légalité entre 2 entiers est plus rapide que dautres tests dégalité.
Si votre critère est un intervalle entre 2 TIMESTAMP ou si la colonne à indexer est de type SMALLINT alors passez votre chemin. Mais si la requête implique de tester des égalités sur une colonne texte alors ce principe est potentiellement intéressant. La réalité rejoint-elle la théorie dans un environnement disposant dune mémoire vive suffisante pour mettre complètement en cache les données ? Démonstration avec PostgreSQL 10 beta :
Les données varchar de la colonne devise ont toujours une longueur de 32 caractères. Le Hash Index obtenu a été créé en 3s7 et sa taille est inférieure (32Mo) à celle de lindex B-Tree (56Mo) qui a été créé en 7s8.
Un plan dexécution impliquant une boucle comprenant 50000 index scan montre un net avantage de lindex Hash (0s55) sur lindex B-Tree (1s). Il faut noter que lindex B-Tree dont lutilisation a été implicitement conseillée au planner en positionnant random_page_cost à 1 nest pas convaincant. En effet, sans index, la requête basée sur un hash join exécuté à 100% en mémoire durait 0s9.
Les index B-Tree permettent depuis la version 9.2 déviter complètement de passer par la table lorsque toutes les colonnes nécessaires à la requête sont indexées. Les Index Hash tiennent-ils toujours la comparaison contre un index B-Tree composite adapté à la requête exécutée dans la première partie ? Démonstration :
LIndex Only Scan a un effet positif puisque le temps passe sous la seconde, il est même possible de passer à 0s54. Mais il faut dabord noter que lIndex Only Scan nest possible que parce le B-Tree composite a été construit spécialement pour cette requête. Si par la suite nous nous intéressions à la colonne MASSE en plus de la colonne IDU lavantage serait annulé.
Il faut ensuite noter que le temps consacré à créer lindex est passé à 8s9 et quil occupe 74Mo despace disque. Pour permettre de réaliser une jointure hash en mémoire, le paramètre work_mem a par ailleurs été augmenté dans la session (32Mo au lieu de 4Mo). Cette augmentation générale des moyens est cependant tout juste suffisante pour battre le Hash Index et ses 0s55.
Lindexation hash confirme donc bien en pratique son avantage théorique dans un cas qui lui est favorable. Mais attention aux excès denthousiasme !