PostgreSQL
 sql >> Base de données >  >> RDS >> PostgreSQL

Index PostgreSQL sur JSON

Vos deux autres index ne fonctionneront pas simplement parce que le ->> l'opérateur renvoie text , alors que vous avez évidemment le jsonb classes d'opérateurs d'égrenage à l'esprit. Notez que vous ne mentionnez que json , mais vous avez en fait besoin de jsonb pour des capacités d'indexation avancées.

Pour élaborer la meilleure stratégie d'indexation, vous devez définir plus précisément les requêtes à couvrir. Vous ne vous intéressez qu'aux vaches ? Ou tous les animaux / toutes les balises ? Quels opérateurs sont possibles ? Votre document JSON inclut-il également des clés non animales ? Que faire de ceux-là ? Voulez-vous inclure des lignes dans l'index où les vaches (ou autre) n'apparaissent pas du tout dans le document JSON ?

En supposant :

  • Nous ne nous intéressons qu'aux vaches au premier niveau de nidification.
  • La valeur est toujours un integer valide .
  • Les rangées sans vaches ne nous intéressent pas.

Je suggère un index btree fonctionnel, un peu comme vous l'avez déjà fait, mais transmettez la valeur à integer . Je suppose que vous ne voudriez pas que la comparaison soit évaluée en tant que text (où '2' est supérieur à '1111').

CREATE INDEX animal_index ON farm (((animal ->> 'cow')::int));  -- !

L'ensemble supplémentaire de parenthèses est nécessaire pour que la sténographie cast rende la syntaxe de l'expression d'index non ambiguë.

Utilisez la même expression dans vos requêtes pour que Postgres réalise que l'index est applicable :

SELECT * FROM farm WHERE (animal ->> 'cow')::int > 3;

Si vous avez besoin d'un jsonb plus générique index, considérez :

  • Quel est l'index approprié pour interroger des structures dans des tableaux dans Postgres jsonb ?

Pour un connu, statique, trivial nombre d'animaux (comme vous l'avez commenté), je suggère des index partiels comme :

CREATE INDEX animal_index ON farm (((animal ->> 'cow')::int))
WHERE (animal ->> 'cow') IS NOT NULL;

CREATE INDEX animal_index ON farm (((animal ->> 'chicken')::int))
WHERE (animal ->> 'chicken') IS NOT NULL;

Etc.

Vous devrez peut-être ajouter la condition d'index à la requête :

SELECT * FROM farm
WHERE (animal ->> 'cow')::int > 3
AND   (animal ->> 'cow') IS NOT NULL; 

Cela peut sembler redondant, mais peut être nécessaire. Tester avec ANALYZE !