2017-12-13 2 views
0

Ich habe die folgende Abfrage aufvermeiden Wiederholung Bedingung in Auswahlabfrage

postgresql ausgeführt werden
SELECT COUNT(DISTINCT id_client) FROM contract c 
INNER JOIN bundle b ON c.bundle_id = b.id 
INNER JOIN payment_method pm ON pm.id = c.payment_method_id 
WHERE country_id=1 AND b.platform_id=1 AND pm.name <> 'RIB' 
    AND CONDITION_1 
    AND id_client NOT IN (
    SELECT id_client FROM contract c1 
    INNER JOIN bundle b1 ON (c1.bundle_id = b1.id) 
    INNER JOIN payment_method pm1 ON pm1.id = c1.payment_method_id 
    WHERE c1.country_id=1 AND b1.platform_id=1 AND pm1.name <> 'RIB' 
     AND CONDITION_2); 

Ich mag es nicht, weil es die gleiche Abfrage ist zweimal wiederholt, mit Ausnahme von CONDITION_1 und CONDITION_2 (und ich habe ein weiteres Beispiel wo es 3 mal wiederholt wird).

Es ist auch sehr langsam.

Ich habe versucht, es wie folgt zu umschreiben:

WITH 
filter_cpm AS (
    SELECT * FROM contract c 
    INNER JOIN bundle b ON b.id = c.bundle_id 
    INNER JOIN payment_method pm ON pm.id = c.payment_method_id 
     WHERE c.country_id = 1 AND b.platform_id = 1 AND pm.name <> 'RIB' 
) 
SELECT COUNT(DISTINCT id_client) FROM filter_cpm 
    WHERE CONDITION_1 
     AND id_client NOT IN (
     SELECT id_client FROM filter_cpm 
     WHERE CONDITION_2); 

Jetzt ist es trocken, aber es ist zwei mal langsamer.

Wie kann ich die Abfrage neu schreiben, um die gleiche (oder bessere) Leistung zu haben?

EDIT: Ich kann nicht zwei Bedingungen mit UND verbinden. Wenn beispielsweise CONDITION_1 und CONDITION_2 VIP sind, möchte ich Kunden auswählen, die von NOT VIP zu VIP re-qualifiziert wurden.

Antwort

1

Sie aus dem allgemeinen Tabellenausdruck zweimal wählen, eine Outer-Join verwendet:

WITH filter_cpm AS (SELECT * 
         FROM CONTRACT c 
         INNER JOIN BUNDLE b 
         ON b.ID = c.BUNDLE_ID 
         INNER JOIN PAYMENT_METHOD pm 
         ON pm.ID = c.PAYMENT_METHOD_ID 
         WHERE c.COUNTRY_ID = 1 AND 
          b.PLATFORM_ID = 1 AND 
          pm.NAME <> 'RIB') 
SELECT COUNT(DISTINCT fc1.ID_CLIENT) 
    FROM filter_cpm fc1 
    LEFT OUTER JOIN filter_cpm fc2 
    ON fc2.ID_CLIENT = fc1.ID_CLIENT AND 
     CONDITION_2 
    WHERE fc1.CONDITION_1 AND 
     fc2.ID_CLIENT IS NULL 

Best of luck.

+0

Danke für die Antwort. Ja, Ihre Abfrage liefert das gleiche Ergebnis wie zwei meiner Abfragen. Und es dauert 3 Minuten, genauso wie meine zweite Abfrage. Die erste wird in 1min30 –

+0

ausgeführt. Sie könnten FILTER_CPM einschränken, um nur die Felder zurückzuziehen, die Sie tatsächlich benötigen. Von dem, was ich sehen kann, ist das einzige Feld, das tatsächlich verwendet wird, ID_CLIENT, aber ich habe natürlich keine Ahnung, was CONDITION_1 und CONDITION_2 sein könnten. Erstellen Sie dann vollständige Indizes für CONTRACT, BUNDLE und PAYMENT_METHOD für alle beteiligten Felder und prüfen Sie, ob Sie FULL TABLE SCANs in INDEX SCANs umwandeln können. –

Verwandte Themen