0
votes

Accélérer une opération de jointure coûteuse - une énorme table avec un petit

J'utilise Postgres pour stocker un grand nombre de transactions et essayer de conserver les temps de lecture pour une instruction SELECT SELECT SPECIBLE dans TENS de millisecondes.

Schéma de Tablea (> Userid Int, Idemid Int ). Indexé par UserID P>

schéma de la tableb (1mm lignes): (CatégorieID Int, ItemID Int). Indexé par la catégorieid. Nombre de catégories = 500 et chaque élémentId n'appartient à une catégorie. P>

La requête que je veux optimiser pour lequel me prend actuellement ~ 100 ms à exécuter est la suivante: p>

[('  ->  Hash Semi Join  (cost=159.50..382.67 rows=164 width=50)'),
 ('        Hash Cond: (tableA.itemId = tableB.itemId)'),
 ('        ->  Index Scan using userId on tableA  (cost=0.57..208.31 rows=5185 width=50)'),
 ('              Index Cond: (userId = 4000)'),
 ('        ->  Hash  (cost=117.05..117.05 rows=3350 width=4)'),
 ('              Buckets: 4096  Batches: 1  Memory Usage: 161kB',),
 ('              ->  Index Scan using categoryId on tableB (cost=0.42..117.05 rows=3350 width=4)'),
 ('                    Index Cond: (categoryId = 1002)',), ('Planning time: 0.149 ms',)]


5 commentaires

Avez-vous un plan d'explication pour cette requête? Avez-vous fatigué existe-t-il au lieu d'entrer?


ty pour noter. J'ai ajouté un exemple de plan de requête. Mais pas sûr s'il existe une bonne méthode à cet effet lorsque je veux tirer dans des rangées? Je vais essayer!


Merci pour le plan d'explication. Les analyses d'index semblent raisonnables ici et je vois que cela existe est la même chose / similaire. Rien que je puisse suggérer.


À droite, semble difficile à améliorer sur la requête. Voyez-vous une autre façon d'organiser les colonnes de données - Mix / Match?


C'est un simple arrangement "de la recherche", je ne vois rien d'évident, désolé.


3 Réponses :


1
votes

existe peut-être aidera ici: différence entre existe existant et dans

pour votre requête: xxx


2 commentaires

Merci pour votre suggestion. Postgres donne un plan de requête identique et des horaires d'exécution similaires pour cela que l'équivalent dans J'utilisais plus tôt.


Si cette requête est utilisée fréquente, vous devez appliquer l'index sur les deux tableaux sur ID utilisateur, ItemID et CatégorieId, itemID respectivement, car il y a une analyse d'index dans votre plan de requête.



0
votes

Une autre approche serait de créer une éventail d'élément valide et de filtrer par elle. Ensuite, vous éviterez une opération de participation. Il peut toutefois être plus lent, en fonction de vos données.

select * from TableA 
where userID = x
  and itemID = any((select array_agg(/*DISTINCT */itemID)
                      from TableB
                     where categoryID = y)::int4[])


4 commentaires

Cela ressemble à la même chose que l'original dans question? La jointure de hachage ne semble pas être la partie coûteuse dans le plan de requête.


@ananis je ne peux pas vraiment dire comment ça te sent. J'imagine que vous pouvez simplement le courir et voir par vous-même ...


Thx pour votre suggestion Lukasz, vraiment faux choix de mot par moi :). Je voulais dire que je ne pouvais pas voir pourquoi cela serait-il plus rapide que la requête originale. J'ai essayé et ça sort d'être plus lent.


@ananis Ouais, cela dépend du nombre d'articles à l'intérieur du tableau, si vous souhaitez le tri, si vous l'avez indexé, si vous utilisez des partitions. Je garderais toujours à l'esprit quand vous seriez coincé à l'avenir, car j'ai beaucoup de cas quand cela est plus rapide.



0
votes

J'ai trouvé une voie nette de résoudre ceci en faisant des tavins dénormalisés et en utilisant des clés étrangères Postgres. xxx

Tous les paires d'éléments utilisateur pour une catégorie peuvent maintenant être récupérés en effectuant une sélection de tablier. La contrainte de clé étrangère veille à ce que les lignes de Tablea soient mises à jour si la catégorieID pour tout élément change de tableb. xxx

merci pour vos suggestions!


0 commentaires