【问题标题】:Improve Function performance in Postgresql提高 Postgresql 中的函数性能
【发布时间】:2016-10-12 00:50:00
【问题描述】:

以下函数正在创建一个临时表,然后在其中填充数据。

该临时表应该在单击网站上的按钮时显示。

我尝试提高性能的步骤: 1.修改postgresql.conf文件。 2. 临时表增加索引

CREATE OR REPLACE FUNCTION lastonemonth()
  RETURNS void AS
$BODY$
  DECLARE
  query1 text;
  query2 text;
  var_loop1 RECORD;
  dealerName text;
  cur_minus_2_month text; 
  var_sum_of_quantity numeric;
  var_net_value numeric;
  var_average_price_nsr numeric; 
  BEGIN
  EXECUTE 'DROP TABLE IF EXISTS LOM CASCADE';
  EXECUTE 'CREATE TEMP TABLE LOM ( dealer_name text PRIMARY KEY , sum_of_quantity numeric, net_value numeric, average_price_nsr numeric)';
  EXECUTE 'CREATE UNIQUE INDEX dealer_name_idx ON LOM (dealer_name)';

  query1:= 'SELECT DISTINCT dealer FROM customernotorderdb_temp WHERE month IN ( to_char( now() - interval ''2 month'', ''YYYYMM'') , to_char( now() - interval ''3 month'', ''YYYYMM''))EXCEPT SELECT DISTINCT dealer FROM customernotorderdb_temp WHERE month IN ( to_char( now() - interval ''1 month'', ''YYYYMM''), to_char(now(), ''YYYYMM'') )';
  FOR var_loop1 IN EXECUTE (query1)
  LOOP
      dealerName:= var_loop1.dealer;
      INSERT INTO LOM(dealer_name) VALUES(dealerName);
      EXECUTE 'SELECT month FROM customernotorderdb_temp WHERE dealer LIKE ''%'||dealerName||'%'' AND month IN(to_char( now() - interval ''2 month'', ''YYYYMM''))' INTO cur_minus_2_month;

      --RAISE NOTICE 'cur_minus_2_month( % )', cur_minus_2_month;
      IF cur_minus_2_month IS NOT NULL 
      THEN
          EXECUTE 'SELECT SUM(saleqtypermt) FROM customernotorderdb_temp WHERE dealer LIKE ''%'||dealerName||'%'' AND month IN (to_char( now() - interval ''2 month'', ''YYYYMM''),to_char( now() - interval ''3 month'', ''YYYYMM''),to_char( now() - interval ''4 month'', ''YYYYMM''),to_char( now() - interval ''5 month'', ''YYYYMM''),to_char( now() - interval ''6 month'', ''YYYYMM''),to_char( now() - interval ''7 month'', ''YYYYMM''),to_char( now() -interval ''8 month'', ''YYYYMM''),to_char( now() - interval ''9 month'', ''YYYYMM''),to_char( now() - interval ''10 month'', ''YYYYMM''),to_char( now() - interval ''11 month'', ''YYYYMM''),to_char( now() - interval ''12 month'', ''YYYYMM''),to_char( now() - interval ''13 month'', ''YYYYMM''))' INTO var_sum_of_quantity;
          EXECUTE 'SELECT SUM(basic_value-rate_diff) FROM customernotorderdb_temp WHERE dealer LIKE ''%'||dealerName||'%'' AND month IN (to_char( now() - interval ''2 month'', ''YYYYMM''),to_char( now() - interval ''3 month'', ''YYYYMM''),to_char( now() - interval ''4 month'', ''YYYYMM''),to_char( now() - interval ''5 month'', ''YYYYMM''),to_char( now() - interval ''6 month'', ''YYYYMM''),to_char( now() - interval ''7 month'', ''YYYYMM''),to_char( now() -interval ''8 month'', ''YYYYMM''),to_char( now() - interval ''9 month'', ''YYYYMM''),to_char( now() - interval ''10 month'', ''YYYYMM''),to_char( now() - interval ''11 month'', ''YYYYMM''),to_char( now() - interval ''12 month'', ''YYYYMM''),to_char( now() - interval ''13 month'', ''YYYYMM''))' INTO var_net_value;
          EXECUTE 'SELECT SUM(avgpricensr) FROM customernotorderdb_temp WHERE dealer LIKE ''%'||dealerName||'%'' AND month IN (to_char( now() - interval ''2 month'', ''YYYYMM''),to_char( now() - interval ''3 month'', ''YYYYMM''),to_char( now() - interval ''4 month'', ''YYYYMM''),to_char( now() - interval ''5 month'', ''YYYYMM''),to_char( now() - interval ''6 month'', ''YYYYMM''),to_char( now() - interval ''7 month'', ''YYYYMM''),to_char( now() -interval ''8 month'', ''YYYYMM''),to_char( now() - interval ''9 month'', ''YYYYMM''),to_char( now() - interval ''10 month'', ''YYYYMM''),to_char( now() - interval ''11 month'', ''YYYYMM''),to_char( now() - interval ''12 month'', ''YYYYMM''),to_char( now() - interval ''13 month'', ''YYYYMM''))' INTO var_average_price_nsr;
          --RAISE NOTICE 'A [ %   % ]', dealername,var_net_value;
          UPDATE LOM SET sum_of_quantity=var_sum_of_quantity,
                         net_value=var_net_value,
                         average_price_nsr=var_average_price_nsr 
          WHERE dealer_name=var_loop1.dealer;

      ELSE
          EXECUTE 'SELECT SUM(saleqtypermt) FROM customernotorderdb_temp WHERE dealer LIKE ''%'||dealerName||'%'' AND month IN (to_char( now() - interval ''3 month'', ''YYYYMM''),to_char( now() - interval ''4 month'', ''YYYYMM''),to_char( now() - interval ''5 month'', ''YYYYMM''),to_char( now() - interval ''6 month'', ''YYYYMM''),to_char( now() - interval ''7 month'', ''YYYYMM''),to_char( now() -interval ''8 month'', ''YYYYMM''),to_char( now() - interval ''9 month'', ''YYYYMM''),to_char( now() - interval ''10 month'', ''YYYYMM''),to_char( now() - interval ''11 month'', ''YYYYMM''),to_char( now() - interval ''12 month'', ''YYYYMM''),to_char( now() - interval ''13 month'', ''YYYYMM''),to_char( now() - interval ''14 month'', ''YYYYMM''))' INTO var_sum_of_quantity;
          EXECUTE 'SELECT SUM(basic_value-rate_diff) FROM customernotorderdb_temp WHERE dealer LIKE ''%'||dealerName||'%'' AND month IN (to_char( now() - interval ''3 month'', ''YYYYMM''),to_char( now() - interval ''4 month'', ''YYYYMM''),to_char( now() - interval ''5 month'', ''YYYYMM''),to_char( now() - interval ''6 month'', ''YYYYMM''),to_char( now() - interval ''7 month'', ''YYYYMM''),to_char( now() -interval ''8 month'', ''YYYYMM''),to_char( now() - interval ''9 month'', ''YYYYMM''),to_char( now() - interval ''10 month'', ''YYYYMM''),to_char( now() - interval ''11 month'', ''YYYYMM''),to_char( now() - interval ''12 month'', ''YYYYMM''),to_char( now() - interval ''13 month'', ''YYYYMM''),to_char( now() - interval ''14 month'', ''YYYYMM''))' INTO var_net_value;
          EXECUTE 'SELECT SUM(avgpricensr) FROM customernotorderdb_temp WHERE dealer LIKE ''%'||dealerName||'%'' AND month IN (to_char( now() - interval ''3 month'', ''YYYYMM''),to_char( now() - interval ''4 month'', ''YYYYMM''),to_char( now() - interval ''5 month'', ''YYYYMM''),to_char( now() - interval ''6 month'', ''YYYYMM''),to_char( now() - interval ''7 month'', ''YYYYMM''),to_char( now() -interval ''8 month'', ''YYYYMM''),to_char( now() - interval ''9 month'', ''YYYYMM''),to_char( now() - interval ''10 month'', ''YYYYMM''),to_char( now() - interval ''11 month'', ''YYYYMM''),to_char( now() - interval ''12 month'', ''YYYYMM''),to_char( now() - interval ''13 month'', ''YYYYMM''),to_char( now() - interval ''14 month'', ''YYYYMM''))' INTO var_average_price_nsr;
          --RAISE NOTICE 'B [ %  % ]', dealername,var_net_value;
          UPDATE LOM SET sum_of_quantity=var_sum_of_quantity,net_value=var_net_value,average_price_nsr=var_average_price_nsr WHERE dealer_name=var_loop1.dealer;
      END IF;         
 END LOOP;
END;
$BODY$
  LANGUAGE plpgsql VOLATILE 

【问题讨论】:

  • 您没有在表格上运行 ANALYZE。较新的 drop temp 表,改为截断它。然后就可以使用静态SQL了。
  • 你不需要函数;你不需要循环,你不需要 plpgsql。该函数有效地执行INSERT INTO LOM(...) SELECT dealer_name, SUM(xxx0), ... FROM customernotorderdb_temp GROUP BY dealer_name(以及其他一些聚合和选择)
  • 经过上述建议后,代码如下:
  • WHERE dealer LIKE ''%'||dealerName||'%'' 为什么在这里使用通配符?你从同一张桌子上得到了经销商的名字!

标签: sql performance postgresql function


【解决方案1】:

首先,您似乎将月份存储为字符串并手动与字符串进行日期比较。那会让它慢下来。你能用 Postgres 日期类型或整数来代替吗?

对于其他事情,如果不知道您的数据库布局和统计信息,我真的无法判断,但这里是优化查询的基本方法:

  1. 使用 psql 或其他工具打开新连接。
  2. set enable_seqscan = off,仅在此会话中禁用查询计划器中的 seq 扫描(除非完全必要)。
  3. 在查询之前运行EXPLAIN 以查看哪些查询被强制扫描大表。如果您看到任何 SEQ SCANs,请添加索引。

【讨论】:

  • "EXPLAIN ANALYZE SELECT lastonemonth();st=0.00..0.26 rows=1 width=0) (实际时间=16959.720..16959.721 rows=1 loops=1)" "总运行时间:16959.734毫秒”
  • 非常感谢,现在代码的效率是 EXPLAIN ANALYZE SELECT lastonemonth();"Result (cost=0.00..0.26 rows=1 width=0) (实际时间=2783.845..2783.845 rows=1 loops=1)" "总运行时间:2783.859 毫秒"
  • 不错。你改变了什么?您没有发布 EXPLAIN 生成的查询计划。
  • 1.删除通配符 % 2. 添加显式索引。 3. if 块下将三个execute 语句合并为一个 4. 修改postgresql.conf 文件设置 5. 从函数中删除'CREATE' 和'DROP' 语句 6. 删除减速部分的一个变量
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-12-17
  • 2011-09-30
  • 2015-07-11
  • 2014-03-20
  • 2011-01-06
  • 2021-08-03
  • 2013-02-17
相关资源
最近更新 更多