Comment accélérer le tri ORDER BY lors de l'utilisation de l'index GIN dans PostgreSQL?

12

J'ai une table comme celle-ci:

CREATE TABLE products (
  id serial PRIMARY KEY, 
  category_ids integer[],
  published boolean NOT NULL,
  score integer NOT NULL,
  title varchar NOT NULL);

Un produit peut appartenir à plusieurs catégories. category_idsLa colonne contient une liste des identifiants de toutes les catégories de produits.

La requête typique ressemble à ceci (toujours à la recherche d'une seule catégorie):

SELECT * FROM products WHERE published
  AND category_ids @> ARRAY[23465]
ORDER BY score DESC, title
LIMIT 20 OFFSET 8000;

Pour l'accélérer, j'utilise l'index suivant:

CREATE INDEX idx_test1 ON products
  USING GIN (category_ids gin__int_ops) WHERE published;

Celui-ci aide beaucoup à moins qu'il n'y ait trop de produits dans une catégorie. Il filtre rapidement les produits qui appartiennent à cette catégorie, mais il y a ensuite une opération de tri qui doit être effectuée à la dure (sans index).

Une btree_ginextension installée m'a permis de construire un index GIN multi-colonnes comme ceci:

CREATE INDEX idx_test2 ON products USING GIN (
  category_ids gin__int_ops, score, title) WHERE published;

Mais Postgres ne veut pas l'utiliser pour le tri . Même lorsque je supprime le DESCspécificateur dans la requête.

Toute approche alternative pour optimiser la tâche est la bienvenue.


Information additionnelle:

  • PostgreSQL 9.4, avec extension intarray
  • le nombre total de produits est actuellement de 260 000 mais devrait croître de manière significative (jusqu'à 10 millions, il s'agit d'une plateforme de commerce électronique multi-locataire)
  • produits par catégorie 1..10000 (peut atteindre 100 000), la moyenne est inférieure à 100 mais les catégories avec un grand nombre de produits ont tendance à attirer beaucoup plus de demandes

Le plan de requête suivant a été obtenu à partir d'un système de test plus petit (4680 produits dans la catégorie sélectionnée, 200k produits au total dans le tableau):

Limit  (cost=948.99..948.99 rows=1 width=72) (actual time=82.330..82.341 rows=20 loops=1)
  ->  Sort  (cost=948.37..948.99 rows=245 width=72) (actual time=80.231..81.337 rows=4020 loops=1)
        Sort Key: score, title
        Sort Method: quicksort  Memory: 928kB
        ->  Bitmap Heap Scan on products  (cost=13.90..938.65 rows=245 width=72) (actual time=1.919..16.044 rows=4680 loops=1)
              Recheck Cond: ((category_ids @> '{292844}'::integer[]) AND published)
              Heap Blocks: exact=3441
              ->  Bitmap Index Scan on idx_test2  (cost=0.00..13.84 rows=245 width=0) (actual time=1.185..1.185 rows=4680 loops=1)
                    Index Cond: (category_ids @> '{292844}'::integer[])
Planning time: 0.202 ms
Execution time: 82.404 ms

Remarque # 1 : 82 ms peuvent ne pas sembler si effrayantes, mais c'est parce que le tampon de tri tient dans la mémoire. Une fois que j'ai sélectionné toutes les colonnes de la table des produits ( SELECT * FROM ...et dans la vie réelle, il y a environ 60 colonnes), le Sort Method: external merge Disk: 5696kBtemps d'exécution double. Et ce n'est que pour 4680 produits.

Point d'action n ° 1 (provient de la note n ° 1): afin de réduire l'empreinte mémoire de l'opération de tri et donc d'accélérer un peu, il serait sage de récupérer, trier et limiter les identifiants de produit d'abord, puis de récupérer les enregistrements complets:

SELECT * FROM products WHERE id IN (
  SELECT id FROM products WHERE published AND category_ids @> ARRAY[23465]
  ORDER BY score DESC, title LIMIT 20 OFFSET 8000
) ORDER BY score DESC, title;

Cela nous ramène à Sort Method: quicksort Memory: 903kBet ~ 80 ms pour 4680 produits. Peut encore être lent lorsque le nombre de produits atteint 100 000.

Yaroslav Stavnichiy
la source
Sur cette page: hlinnaka.iki.fi/2014/03/28/… il y a un commentaire selon lequel btree_gin ne peut pas être utilisé pour le tri.
Mladen Uzelac
OK, j'ai reformulé le titre pour permettre plus d'options.
Yaroslav Stavnichiy
Recherchez-vous toujours une seule catégorie? Et veuillez fournir des informations plus basiques: version Postgres, cardinalités, lignes par catégorie (min / moy / max). examinez les instructions dans les informations de balise pour postgresql-performance . Et: scorepeut être NULL, mais vous triez toujours par score DESC, non score DESC NULLS LAST. L'un ou l'autre ne semble pas correct ...
Erwin Brandstetter
J'ai ajouté des informations supplémentaires comme demandé. Je suis toujours à la recherche d'une seule catégorie. Et scoreen fait, ce n'est PAS NULL - j'ai corrigé la définition de la table.
Yaroslav Stavnichiy

Réponses:

9

J'ai fait beaucoup d'expérimentations et voici mes résultats.

GIN et tri

L'index GIN actuellement (à partir de la version 9.4) ne peut pas aider à la commande .

Parmi les types d'index actuellement pris en charge par PostgreSQL, seul B-tree peut produire une sortie triée - les autres types d'index renvoient des lignes correspondantes dans un ordre non spécifié, dépendant de l'implémentation.

work_mem

Merci Chris d'avoir signalé ce paramètre de configuration . La valeur par défaut est 4 Mo, et dans le cas où votre jeu d'enregistrements est plus grand, l'augmentation work_memà la valeur appropriée (disponible à partir de EXPLAIN ANALYSE) peut accélérer considérablement les opérations de tri.

ALTER SYSTEM SET work_mem TO '32MB';

Redémarrez le serveur pour que les modifications prennent effet, puis revérifiez:

SHOW work_mem;

Requête d'origine

J'ai rempli ma base de données avec 650k produits avec certaines catégories contenant jusqu'à 40k produits. J'ai simplifié un peu la requête en supprimant la publishedclause:

SELECT * FROM products WHERE category_ids @> ARRAY [248688]
ORDER BY score DESC, title LIMIT 10 OFFSET 30000;

Limit  (cost=2435.62..2435.62 rows=1 width=1390) (actual time=1141.254..1141.256 rows=10 loops=1)
  ->  Sort  (cost=2434.00..2435.62 rows=646 width=1390) (actual time=1115.706..1140.513 rows=30010 loops=1)
        Sort Key: score, title
        Sort Method: external merge  Disk: 29656kB
        ->  Bitmap Heap Scan on products  (cost=17.01..2403.85 rows=646 width=1390) (actual time=11.831..25.646 rows=41666 loops=1)
              Recheck Cond: (category_ids @> '{248688}'::integer[])
              Heap Blocks: exact=6471
              ->  Bitmap Index Scan on idx_products_category_ids_gin  (cost=0.00..16.85 rows=646 width=0) (actual time=10.140..10.140 rows=41666 loops=1)
                    Index Cond: (category_ids @> '{248688}'::integer[])
Planning time: 0.288 ms
Execution time: 1146.322 ms

Comme nous pouvons le voir, ce work_memn'était pas suffisant, nous en avions Sort Method: external merge Disk: 29656kB(le nombre ici est approximatif, il a besoin d'un peu plus de 32 Mo pour le tri rapide en mémoire).

Réduisez l'empreinte mémoire

Ne sélectionnez pas les enregistrements complets pour le tri, utilisez les identifiants, appliquez le tri, le décalage et la limite, puis chargez seulement 10 enregistrements dont nous avons besoin:

SELECT * FROM products WHERE id in (
  SELECT id FROM products WHERE category_ids @> ARRAY[248688]
  ORDER BY score DESC, title LIMIT 10 OFFSET 30000
) ORDER BY score DESC, title;

Sort  (cost=2444.10..2444.11 rows=1 width=1390) (actual time=707.861..707.862 rows=10 loops=1)
  Sort Key: products.score, products.title
  Sort Method: quicksort  Memory: 35kB
  ->  Nested Loop  (cost=2436.05..2444.09 rows=1 width=1390) (actual time=707.764..707.803 rows=10 loops=1)
        ->  HashAggregate  (cost=2435.63..2435.64 rows=1 width=4) (actual time=707.744..707.746 rows=10 loops=1)
              Group Key: products_1.id
              ->  Limit  (cost=2435.62..2435.62 rows=1 width=72) (actual time=707.732..707.734 rows=10 loops=1)
                    ->  Sort  (cost=2434.00..2435.62 rows=646 width=72) (actual time=704.163..706.955 rows=30010 loops=1)
                          Sort Key: products_1.score, products_1.title
                          Sort Method: quicksort  Memory: 7396kB
                          ->  Bitmap Heap Scan on products products_1  (cost=17.01..2403.85 rows=646 width=72) (actual time=11.587..35.076 rows=41666 loops=1)
                                Recheck Cond: (category_ids @> '{248688}'::integer[])
                                Heap Blocks: exact=6471
                                ->  Bitmap Index Scan on idx_products_category_ids_gin  (cost=0.00..16.85 rows=646 width=0) (actual time=9.883..9.883 rows=41666 loops=1)
                                      Index Cond: (category_ids @> '{248688}'::integer[])
        ->  Index Scan using products_pkey on products  (cost=0.42..8.45 rows=1 width=1390) (actual time=0.004..0.004 rows=1 loops=10)
              Index Cond: (id = products_1.id)
Planning time: 0.682 ms
Execution time: 707.973 ms

Remarque Sort Method: quicksort Memory: 7396kB. Le résultat est bien meilleur.

JOIN et index B-tree supplémentaire

Comme Chris l'a conseillé, j'ai créé un index supplémentaire:

CREATE INDEX idx_test7 ON products (score DESC, title);

J'ai d'abord essayé de rejoindre comme ceci:

SELECT * FROM products NATURAL JOIN
  (SELECT id FROM products WHERE category_ids @> ARRAY[248688]
  ORDER BY score DESC, title LIMIT 10 OFFSET 30000) c
ORDER BY score DESC, title;

Le plan de requête diffère légèrement mais le résultat est le même:

Sort  (cost=2444.10..2444.11 rows=1 width=1390) (actual time=700.747..700.747 rows=10 loops=1)
  Sort Key: products.score, products.title
  Sort Method: quicksort  Memory: 35kB
  ->  Nested Loop  (cost=2436.05..2444.09 rows=1 width=1390) (actual time=700.651..700.690 rows=10 loops=1)
        ->  HashAggregate  (cost=2435.63..2435.64 rows=1 width=4) (actual time=700.630..700.630 rows=10 loops=1)
              Group Key: products_1.id
              ->  Limit  (cost=2435.62..2435.62 rows=1 width=72) (actual time=700.619..700.619 rows=10 loops=1)
                    ->  Sort  (cost=2434.00..2435.62 rows=646 width=72) (actual time=697.304..699.868 rows=30010 loops=1)
                          Sort Key: products_1.score, products_1.title
                          Sort Method: quicksort  Memory: 7396kB
                          ->  Bitmap Heap Scan on products products_1  (cost=17.01..2403.85 rows=646 width=72) (actual time=10.796..32.258 rows=41666 loops=1)
                                Recheck Cond: (category_ids @> '{248688}'::integer[])
                                Heap Blocks: exact=6471
                                ->  Bitmap Index Scan on idx_products_category_ids_gin  (cost=0.00..16.85 rows=646 width=0) (actual time=9.234..9.234 rows=41666 loops=1)
                                      Index Cond: (category_ids @> '{248688}'::integer[])
        ->  Index Scan using products_pkey on products  (cost=0.42..8.45 rows=1 width=1390) (actual time=0.004..0.004 rows=1 loops=10)
              Index Cond: (id = products_1.id)
Planning time: 1.015 ms
Execution time: 700.918 ms

En jouant avec différents décalages et nombre de produits, je n'ai pas pu faire en sorte que PostgreSQL utilise un index B-tree supplémentaire.

Je suis donc allé de façon classique et j'ai créé une table de jonction :

CREATE TABLE prodcats AS SELECT id AS product_id, unnest(category_ids) AS category_id FROM products;
CREATE INDEX idx_prodcats_cat_prod_id ON prodcats (category_id, product_id);

SELECT p.* FROM products p JOIN prodcats c ON (p.id=c.product_id)
WHERE c.category_id=248688
ORDER BY p.score DESC, p.title LIMIT 10 OFFSET 30000;

Limit  (cost=122480.06..122480.09 rows=10 width=1390) (actual time=1290.360..1290.362 rows=10 loops=1)
  ->  Sort  (cost=122405.06..122509.00 rows=41574 width=1390) (actual time=1264.250..1289.575 rows=30010 loops=1)
        Sort Key: p.score, p.title
        Sort Method: external merge  Disk: 29656kB
        ->  Merge Join  (cost=50.46..94061.13 rows=41574 width=1390) (actual time=117.746..182.048 rows=41666 loops=1)
              Merge Cond: (p.id = c.product_id)
              ->  Index Scan using products_pkey on products p  (cost=0.42..90738.43 rows=646067 width=1390) (actual time=0.034..116.313 rows=210283 loops=1)
              ->  Index Only Scan using idx_prodcats_cat_prod_id on prodcats c  (cost=0.43..1187.98 rows=41574 width=4) (actual time=0.022..7.137 rows=41666 loops=1)
                    Index Cond: (category_id = 248688)
                    Heap Fetches: 0
Planning time: 0.873 ms
Execution time: 1294.826 ms

N'utilisant toujours pas l'indice B-tree, l'ensemble de résultats ne correspondait pas work_mem, d'où de mauvais résultats.

Mais dans certaines circonstances, ayant un grand nombre de produits et un petit décalage, PostgreSQL décide maintenant d'utiliser l'index B-tree:

SELECT p.* FROM products p JOIN prodcats c ON (p.id=c.product_id)
WHERE c.category_id=248688
ORDER BY p.score DESC, p.title LIMIT 10 OFFSET 300;

Limit  (cost=3986.65..4119.51 rows=10 width=1390) (actual time=264.176..264.574 rows=10 loops=1)
  ->  Nested Loop  (cost=0.98..552334.77 rows=41574 width=1390) (actual time=250.378..264.558 rows=310 loops=1)
        ->  Index Scan using idx_test7 on products p  (cost=0.55..194665.62 rows=646067 width=1390) (actual time=0.030..83.026 rows=108037 loops=1)
        ->  Index Only Scan using idx_prodcats_cat_prod_id on prodcats c  (cost=0.43..0.54 rows=1 width=4) (actual time=0.001..0.001 rows=0 loops=108037)
              Index Cond: ((category_id = 248688) AND (product_id = p.id))
              Heap Fetches: 0
Planning time: 0.585 ms
Execution time: 264.664 ms

Ceci est en fait assez logique car l'index B-tree ici ne produit pas de résultat direct, il est uniquement utilisé comme guide pour le scan séquentiel.

Comparons avec la requête GIN:

SELECT * FROM products WHERE id in (
  SELECT id FROM products WHERE category_ids @> ARRAY[248688]
  ORDER BY score DESC, title LIMIT 10 OFFSET 300
) ORDER BY score DESC, title;

Sort  (cost=2519.53..2519.55 rows=10 width=1390) (actual time=143.809..143.809 rows=10 loops=1)
  Sort Key: products.score, products.title
  Sort Method: quicksort  Memory: 35kB
  ->  Nested Loop  (cost=2435.14..2519.36 rows=10 width=1390) (actual time=143.693..143.736 rows=10 loops=1)
        ->  HashAggregate  (cost=2434.71..2434.81 rows=10 width=4) (actual time=143.678..143.680 rows=10 loops=1)
              Group Key: products_1.id
              ->  Limit  (cost=2434.56..2434.59 rows=10 width=72) (actual time=143.668..143.670 rows=10 loops=1)
                    ->  Sort  (cost=2433.81..2435.43 rows=646 width=72) (actual time=143.642..143.653 rows=310 loops=1)
                          Sort Key: products_1.score, products_1.title
                          Sort Method: top-N heapsort  Memory: 68kB
                          ->  Bitmap Heap Scan on products products_1  (cost=17.01..2403.85 rows=646 width=72) (actual time=11.625..31.868 rows=41666 loops=1)
                                Recheck Cond: (category_ids @> '{248688}'::integer[])
                                Heap Blocks: exact=6471
                                ->  Bitmap Index Scan on idx_products_category_ids_gin  (cost=0.00..16.85 rows=646 width=0) (actual time=9.916..9.916 rows=41666 loops=1)
                                      Index Cond: (category_ids @> '{248688}'::integer[])
        ->  Index Scan using products_pkey on products  (cost=0.42..8.45 rows=1 width=1390) (actual time=0.004..0.004 rows=1 loops=10)
              Index Cond: (id = products_1.id)
Planning time: 0.630 ms
Execution time: 143.921 ms

Le résultat de GIN est bien meilleur. J'ai vérifié avec différentes combinaisons de nombre de produits et de décalage, en aucun cas l'approche de la table de jonction n'était meilleure .

La puissance de l'indice réel

Pour que PostgreSQL utilise pleinement l'index pour le tri, tous les WHEREparamètres de requête ainsi que les ORDER BYparamètres doivent résider dans un index B-tree unique. Pour ce faire, j'ai copié les champs de tri du produit vers la table de jonction:

CREATE TABLE prodcats AS SELECT id AS product_id, unnest(category_ids) AS category_id, score, title FROM products;
CREATE INDEX idx_prodcats_1 ON prodcats (category_id, score DESC, title, product_id);

SELECT * FROM products WHERE id in (SELECT product_id FROM prodcats WHERE category_id=248688 ORDER BY score DESC, title LIMIT 10 OFFSET 30000) ORDER BY score DESC, title;

Sort  (cost=2149.65..2149.67 rows=10 width=1390) (actual time=7.011..7.011 rows=10 loops=1)
  Sort Key: products.score, products.title
  Sort Method: quicksort  Memory: 35kB
  ->  Nested Loop  (cost=2065.26..2149.48 rows=10 width=1390) (actual time=6.916..6.950 rows=10 loops=1)
        ->  HashAggregate  (cost=2064.83..2064.93 rows=10 width=4) (actual time=6.902..6.904 rows=10 loops=1)
              Group Key: prodcats.product_id
              ->  Limit  (cost=2064.02..2064.71 rows=10 width=74) (actual time=6.893..6.895 rows=10 loops=1)
                    ->  Index Only Scan using idx_prodcats_1 on prodcats  (cost=0.56..2860.10 rows=41574 width=74) (actual time=0.010..6.173 rows=30010 loops=1)
                          Index Cond: (category_id = 248688)
                          Heap Fetches: 0
        ->  Index Scan using products_pkey on products  (cost=0.42..8.45 rows=1 width=1390) (actual time=0.003..0.003 rows=1 loops=10)
              Index Cond: (id = prodcats.product_id)
Planning time: 0.318 ms
Execution time: 7.066 ms

Et c'est le pire scénario avec un grand nombre de produits dans la catégorie choisie et un grand décalage. Lorsque offset = 300, le temps d'exécution n'est que de 0,5 ms.

Malheureusement, le maintien d'une telle table de jonction nécessite un effort supplémentaire. Cela peut être accompli via des vues matérialisées indexées, mais cela n'est utile que lorsque vos données sont rarement mises à jour, car l'actualisation de cette vue matérialisée est une opération assez lourde.

Donc, je reste avec l'index GIN jusqu'à présent, avec une work_memrequête d'empreinte mémoire augmentée et réduite.

Yaroslav Stavnichiy
la source
Vous n'avez pas besoin de redémarrer pour modifier le work_memparamètre général dans postgresql.conf. Le rechargement suffit. Et permettez-moi de mettre en garde contre un réglage work_memtrop élevé à l'échelle mondiale dans un environnement multi-utilisateurs (pas trop bas non plus). Si vous avez des questions plus besoin work_mem, réglez plus pour la session uniquement avec SET- ou tout simplement la transaction avec SET LOCAL. Voir: dba.stackexchange.com/a/48633/3684
Erwin Brandstetter
Quelle excellente réponse. M'a beaucoup aidé, en particulier avec le disque -> opération de tri en mémoire, changement rapide pour une grande victoire, merci!
Ricardo Villamil
4

Voici quelques conseils rapides qui peuvent vous aider à améliorer vos performances. Je vais commencer par la pointe la plus simple, qui est presque sans effort de votre part, et passer à la pointe la plus difficile après la première.

1. work_mem

Donc, je vois tout de suite qu'un type signalé dans votre plan d'explication Sort Method: external merge Disk: 5696kBconsomme moins de 6 Mo, mais se répand sur le disque. Vous devez augmenter votre work_memparamètre dans votre postgresql.conffichier pour qu'il soit suffisamment grand pour que le tri puisse tenir en mémoire.

EDIT: En outre, après une inspection plus approfondie, je vois qu'après avoir utilisé l'index pour vérifier celui catgory_idsqui correspond à vos critères, l'analyse d'index bitmap est forcée de devenir "avec perte" et doit revérifier la condition lors de la lecture des lignes à partir des pages de tas pertinentes . Reportez-vous à cet article sur postgresql.org pour une explication meilleure que celle que j'ai donnée. : P Le point principal est que votre work_memest trop bas. Si vous n'avez pas réglé les paramètres par défaut sur votre serveur, cela ne fonctionnera pas bien.

Cette correction ne vous prendra essentiellement pas de temps. Un changement pour postgresql.conf, et c'est parti! Reportez-vous à cette page de réglage des performances pour plus de conseils.

2. Changement de schéma

Ainsi, vous avez pris la décision dans votre conception de schéma de dénormaliser le category_idsen un tableau entier, ce qui vous oblige ensuite à utiliser un index GIN ou GIST pour obtenir un accès rapide. D'après mon expérience, votre choix d'un index GIN sera plus rapide pour les lectures qu'un GIST, donc dans ce cas, vous avez fait le bon choix. Cependant, GIN est un index non trié; penser plus comme une valeur clé, où l'égalité prédicats sont faciles à vérifier, mais des opérations telles que WHERE >, WHERE <ou ORDER BYne sont pas facilitées par l'indice.

Une approche décente serait de normaliser votre conception en utilisant une table de pont / table de jonction , utilisée pour spécifier les relations plusieurs-à-plusieurs dans les bases de données.

Dans ce cas, vous avez plusieurs catégories et un ensemble d'entiers correspondants category_id, et vous avez de nombreux produits et leurs product_ids correspondants . Au lieu d'une colonne dans votre table de produit qui est un tableau entier de category_ids, supprimez cette colonne de tableau de votre schéma et créez une table en tant que

CREATE TABLE join_products_categories (product_id int, category_id int);

Ensuite, vous pouvez générer des indices B-tree sur les deux colonnes de la table bridge,

CREATE INDEX idx_products_in_join_table ON join_products_categories (product_id);
CREATE INDEX idx_products_in_join_table ON join_products_categories (category_id);

Juste mon humble avis, mais ces changements peuvent faire une grande différence pour vous. Essayez ce work_memchangement en premier lieu, à tout le moins.

Bonne chance!

ÉDITER:

Créer un index supplémentaire pour faciliter le tri

Donc, si au fil du temps votre gamme de produits se développe, certaines requêtes peuvent renvoyer de nombreux résultats (des milliers, des dizaines de milliers?), Mais qui ne peuvent être qu'un petit sous-ensemble de votre gamme de produits totale. Dans ces cas, le tri peut même être assez coûteux s'il est effectué en mémoire, mais un index conçu de manière appropriée peut être utilisé pour faciliter le tri.

Voir la documentation officielle de PostgreSQL décrivant les index et ORDER BY .

Si vous créez un index correspondant à vos ORDER BYexigences

CREATE INDEX idx_product_sort ON products (score DESC, title);

Postgres optimisera et décidera alors si l'utilisation de l'index ou l'exécution d'un tri explicite sera plus rentable. Gardez à l'esprit qu'il n'y a aucune garantie que Postgres utilisera l'index; il cherchera à optimiser les performances et à choisir entre l'utilisation de l'index ou le tri explicite. Si vous créez cet index, surveillez-le pour voir s'il est suffisamment utilisé pour justifier sa création et supprimez-le si la plupart de vos tris sont effectués de manière explicite.

Pourtant, à ce stade, votre plus grand rapport qualité-prix en utilisera probablement plus work_mem, mais il existe des cas où l'index peut prendre en charge le tri.

Chris
la source
Je pensais également à utiliser une table de jonction pour éviter le GIN. Mais vous n'avez pas précisé en quoi cela va aider au tri. Je pense que ça n'aidera pas. J'ai essayé de joindre la table des produits avec un ensemble d'identifiants de produits collectés via la requête GIN, qui, je pense, est assez similaire à la jointure que vous proposez, et cette opération n'a pas pu utiliser l'index b-tree sur le score et le titre. Peut-être que j'ai construit un mauvais index. Pourriez-vous nous en dire plus?
Yaroslav Stavnichiy
Toutes mes excuses, je n'ai peut-être pas expliqué assez clairement. La modification de votre work_memconfiguration était destinée à corriger votre problème de «tri sur le disque», ainsi que votre problème de vérification de l'état. À mesure que le nombre de produits augmente, vous devrez peut-être disposer d'un index supplémentaire pour trier. Veuillez consulter mes modifications ci-dessus pour obtenir des éclaircissements.
Chris