2016-12-12 4 views
0

Ich habe eine ziemlich komplexe SQL-Anweisung in meiner PostgreSQL-Datenbank, die ich als Grundlage in mehreren Ansichten verwenden. Aber in dieser Anweisung wird eine Summenaggregatfunktion mehrmals aufgerufen. Ich versuche nun, diese Ansichten zu optimieren, indem ich diese Werte mithilfe einer Variablen mehrfach zusammenfasse.PostgreSQL Verwenden Sie einen Wert aus einer Select-Anweisung als eine Variable innerhalb der gleichen Anweisung

Ich weiß, dass ich @myvalue = 1 verwenden kann, aber das ist in pgScript und es kann nicht in einer Ansicht verwendet werden, da es pgScript ist.

Ich habe gelesen über Missbrauch der Konfigurationseinstellungen, um eine Variable zu speichern, aber ich weiß nicht, wie dies mit Ansichten spielt und ich bin nicht wirklich gern solche Hacks.

Der Teil aus dem SQL, den ich in einer Variablen speichern möchte, ist sum(v."Surface")::double precision, die mehrmals wiederholt wird.

Wenn es andere Vorschläge zur Optimierung dieses SQL gibt, bin ich dafür.

CREATE OR REPLACE VIEW mydb."MyTable" AS 
SELECT p."Id", 
    v."FunctionInt", 
    v."TypeInt", 
    sum(v."Surface") AS "SurfaceTotaal", 
    round((sum(v."Surface"::double precision * v."Average")/sum(v."Surface")::double precision)::numeric, 1) AS "Average", 
    round((sum(v."Surface"::double precision * v."E")/sum(v."Surface")::double precision)::numeric, 1) AS "E", 
    round((sum(v."Surface"::double precision * v."E1")/sum(v."Surface")::double precision)::numeric, 1) AS "E1", 
    round((sum(v."Surface"::double precision * v."E2")/sum(v."Surface")::double precision)::numeric, 1) AS "E2", 
    round((sum(v."Surface"::double precision * v."E3")/sum(v."Surface")::double precision)::numeric, 1) AS "E3", 
    round((sum(v."Surface"::double precision * v."M")/sum(v."Surface")::double precision)::numeric, 1) AS "M", 
    round((sum(v."Surface"::double precision * v."M1")/sum(v."Surface")::double precision)::numeric, 1) AS "M1", 
    round((sum(v."Surface"::double precision * v."M2")/sum(v."Surface")::double precision)::numeric, 1) AS "M2", 
    round((sum(v."Surface"::double precision * v."M3")/sum(v."Surface")::double precision)::numeric, 1) AS "M3", 
    round((sum(v."Surface"::double precision * v."G")/sum(v."Surface")::double precision)::numeric, 1) AS "G", 
    round((sum(v."Surface"::double precision * v."G1")/sum(v."Surface")::double precision)::numeric, 1) AS "G1", 
    round((sum(v."Surface"::double precision * v."G2")/sum(v."Surface")::double precision)::numeric, 1) AS "G2", 
    round((sum(v."Surface"::double precision * v."G3")/sum(v."Surface")::double precision)::numeric, 1) AS "G3", 
    round((sum(v."Surface"::double precision * v."G4")/sum(v."Surface")::double precision)::numeric, 1) AS "G4" 
FROM mydb."PTable" p, 
LATERAL ( 
    SELECT 
     v."Id", 
     v."Surface", 
     v."FunctionInt", 
     v."TypeInt", 
     r."YearGroupInt", 
     r."Average", 
     r."En" AS "E", 
     r."En1" AS "E1", 
     r."En2" AS "E2", 
     r."En3" AS "E3", 
     r."Mi" AS "M", 
     r."Mi1" AS "M1", 
     r."Mi2" AS "M2", 
     r."Mi3" AS "M3", 
     r."Gz" AS "G", 
     r."Gz1" AS "G1", 
     r."Gz2" AS "G2", 
     r."Gz3" AS "G3", 
     r."Gz4" AS "G4" 
    FROM mydb."VTable" v 
    JOIN mydb."RTable" r ON 
      v."FunctionInt" = r."FunctionInt" 
      AND v."TypeInt" = r."TypeInt" 
      AND v."YearGroupInt" = r."YearGroupInt" 
    WHERE v."PId" = p."Id") v 
GROUP BY p."Id", v."FunctionInt", v."TypeInt"; 
+0

' create function (var) gibt die Tabelle zurück? –

+4

Sie müssen diese SQL nicht "optimieren". Selbst wenn diese Summe (v. "Surface") in Ihrer Abfrage 1000-mal auftaucht, ist der Optimierer intelligent genug und weiß, dass dies derselbe Wert ist, und berechnet ihn ** nur einmal **, nicht 1000-mal. – krokodilko

+0

@krokodilko, ich hatte auf etwas wie das gehofft, großartig, das beantwortet meine Frage so gut wie alle anderen Vorschläge, abgesehen von den zahlreichen Güssen, die ich loswerden will? –

Antwort

1

Ihre Annahme, dass sum(v."Surface")::double precision mehrfach berechnet wird, ist falsch. Der Planer übernimmt das, testen Sie es selbst.

CREATE TABLE foo AS 
SELECT * FROM generate_series(1,1E7) AS t; 

Dann ..

EXPLAIN ANALYZE SELECT sum(t) FROM foo; 

Nun, versuchen Sie es mit zwei (keine nennenswerte Verlangsamung)

EXPLAIN ANALYZE SELECT sum(t), sum(t) FROM foo; 

Planner nicht Konstanten falten aber

EXPLAIN ANALYZE SELECT sum(t), sum(t+0) FROM foo; 
+0

danke, irgendwelche anderen Vorschläge? –

+0

Ich würde niemals ein Aggregat in einer Ansicht platzieren, die anderswo als Grundlage für andere Ansichten verwendet wird. Der Planer kann 'WHERE'-Bedingungen nicht unterdrücken. Und außerdem. Ich würde auch nicht so tun. Wenn sie doppelt genau sein müssen, speichern Sie sie als doppelte Genauigkeit. Halte sie als doppelte Präzision. Verwenden Sie eine [Math-Funktion] (https://www.postgresql.org/docs/current/static/functions-math.html), wenn Sie mehr oder weniger Präzision benötigen. Ihre Verwendung von Oberfläche sagt mir auch, dass Sie wahrscheinlich PostGIS oder Cube oder Geometrie-Basistypen verwenden sollten. –

+0

Ich stimme zu, Sie missverstehen, ich verwende den Code in mehreren Ansichten, ich verweise nicht auf eine Ansicht in einer anderen (kam zu dem gleichen Schluss, den Sie auf die harte Tour). Surface ist ein Datenfeld vom Typ Integer, das in einer von mir verwendeten Datenbank gespeichert ist. Es handelt sich also nicht um einen Geometrietyp –

Verwandte Themen