0
votes

PostgreSQL Sélectionnez l'endroit où une des deux colonnes en jeu

Mes tables:

  • R1 (ID Serial, A int, B int) - 100K enregistrements
  • R2 (ID, série, Val unique) - Dossiers 40K

    index: R2 (VAL), R1 (A), R1 (B), R1 (B)

    Mon objectif: Obtenez tous les enregistrements de R1 où A ou B sont égaux à Val dans R2

    J'ai pensé à 2 options: xxx

    ou xxx

    dans mon cas spécifique: < ul>

  • La première requête utilise SEQ Scan sur R1 et Scan Hash sur R2.
  • La deuxième analyse utilise SEQ Scan sur R1 et Scan Bitmap sur R2 avec l'index R2 (VAL).

    Je voulais entendre si je peux réécrire la requête de manière meilleure afin de gagner des performances. Au fait, j'utilise pg 9.6

    merci ..


2 commentaires

J'essaierais SELECT R1. * À partir de R1 Rejoignez R2 ON (R1.A = R2.VAL ou R1.B = R2.VAL); - Je ne sais pas si c'est plus rapide que tout sauf Il semble être l'expression SQL la plus propre


... Sauf que cela renvoie une ligne deux fois si a et b apparaît dans r2 , pour éviter que vous ayez besoin de jeter dans un < Code> distinct .


4 Réponses :


0
votes

Et que diriez-vous de

select * from r1 join r2 on r1.a=r2.val
union
select * from r1 join r2 on r1.b=r2.val


2 commentaires

Cela ne semble pas bon, nécessite deux scans de SEQ sur R1 et deux analyses de hachage sur R2


Je ne suis pas d'accord avec l'Union_All - car si A et B finissent par être la même valeur, vous obtiendrez des enregistrements en double ....



1
votes

Je recommanderais:

select r1.*
from r1 join
     r2
     on r1.a = r2.val
union
select r1.*
from r1 join
     r2
     on r1.b = r2.val;


8 commentaires

Comment votre 1ère requête est-elle meilleure que la optique: Sélectionnez * à partir de R1 où existe (sélectionnez * à partir de R2 où R1.a = R2.val ou r1.b = r2.val); ?


@ forpas. . . Je ne sais pas comment Postgres se comporte dans l'utilisation d'index avec le ou dans le où la clause . Il pourrait y avoir des cas où il n'utilise pas d'index approprié.


Donc, cette requête devrait être un cas de test et non une recommandation.


@ forpas - tout ce que vous voulez l'appeler, la première requête semble être la meilleure dans la plupart des cas.


@klin existe deux fois? Je ne le pense pas. Mais, je me tromperais peut-être, c'est pourquoi je l'appelle un cas d'essai.


@forpas - Les deux Existent utilisent deux scannes d'index très rapides uniquement tandis que existe (... ou ...) Besoins bitmapor.


Selon le plan d'exécution, la première option que j'ai suggérée dans mon poste principal est meilleure. La première requête que vous avez suggérée, utilisez une analyse SEQ sur R1 et l'analyse uniquement sur R2. La deuxième requête que vous avez suggérée semble bonne dans l'aspect de la performance mais prend toujours plus de temps que ma première requête.


Par curiosité: dB <> violon.



0
votes

Utilisez un CTE code> que Renvoie tous les val code> S de R2 code> (donc vous numérisez r2 code> une seule fois).
Mais peut-être que cela n'est pas nécessaire si l'optimiseur le fait déjà pour Sélectionnez Val de R2 Code>.
Ensuite, utilisez case code> pour vérifier les 2 cas distincts, de sorte que le 2e cas ( lorsque b dans (sélectionnez Val de CTE) code>) uniquement lorsque le 1er cas ( Lorsque vous êtes dans (sélectionnez Val de CTE) code>) échoue.

WITH cte AS (SELECT VAL FROM R2)
SELECT * FROM R1
WHERE 1 = CASE
  WHEN a IN (SELECT VAL FROM cte) THEN 1
  WHEN b IN (SELECT VAL FROM cte) THEN 1
  ELSE 0
END 


1 commentaires

Il s'agit de la requête la plus proche de l'aspect de la performance s à ma première requête. Ce coût de requête est de 4658, tandis que ma première requête S est de 3385.



0
votes

On dirait dans ce cas spécifique La première requête que j'ai suggérée dans mon commentaire principal fournit la meilleure performance: xxx

@klin a préparé un dbfiddle avec tous les plans d'exécution si quelqu'un veut avoir un regard : https://dbfiddle.uk/?rdbms=postgres_9.5&fiddle=5B50f605262E406C0BAB13710EC121D5 < / p>


0 commentaires