2016-12-12 84 views
0

我在PostgreSQL数据库中有一个相当复杂的SQL语句,我在几个视图中使用它作为基础。但是在这个语句中,总和聚合函数被称为多次。我现在试图通过使用一个变量多次删除汇总这些值来优化这些视图。PostgreSQL使用select语句中的值作为该语句中的变量

我知道我可以使用@myvalue = 1,但这是在pgScript中,它不能在视图中使用,因为它是pgScript。

我已阅读有关滥用配置设置来存储变量,但我不知道这是如何玩视图,我不喜欢这样的黑客。

我想存储在变量中的SQL部分是sum(v."Surface")::double precision,它重复多次。

如果有任何其他建议来优化这个SQL我完全赞成。

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

'创建函数(var)返回表??.. –

+4

你不需要“优化”这个SQL。即使这个'sum(v。“Surface”)'在你的查询中出现了1000次,优化器也足够聪明,并且知道这是相同的值,并且只计算一次**,而不是1000次。 – krokodilko

+0

@krokodilko,我很希望能有这样的事情,很好,这几乎可以回答我的问题,除了我想要摆脱的众多演员之外,还有其他建议吗? –

回答

1

你的假设,即sum(v."Surface")::double precision计算多次不正确。计划者处理这个问题,为自己测试一下。

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

然后..

EXPLAIN ANALYZE SELECT sum(t) FROM foo; 

现在,尝试两(没有明显减慢)

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

计划不折,虽然常量,

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

谢谢,还有其他建议吗? –

+0

我永远不会在其他地方用作其他视图的基础的视图中放置聚合。规划师不能在这里推动WHERE条件。而且,另外。我也不会那样做。如果他们需要双精度,将它们存储为双精度。保持它们的双精度。如果您需要更多或更少的精度,请使用[数学函数](https://www.postgresql.org/docs/current/static/functions-math.html)。你对表面的使用也告诉我你应该使用PostGIS或者立方体或者几何体基类型。 –

+0

我同意,你误解了我在多个视图中使用的代码,我没有在另一个视图中引用一个视图(得出了同样的结论,你说的是艰难的方式)。 Surface是存储在我使用的数据库中的integer类型的数据字段,因此它不是几何类型 –