如何提高 PostgreSQL 中带有游标的函数的性能?

2024-03-04

我有两个嵌套游标的功能。外部游标从源获取客户的付款详细信息,并根据某些业务逻辑插入到目标中。内部光标获取每笔付款的付款详细信息,它接连发生。

Payments 表大约有 125000 行,其中大约 335000 行用于付款详细信息。所有这些行都将迁移到目标表。执行该函数需要两个多小时,数据库CPU使用率高达99%。
我正在使用 PostgreSQL 9.2。

如何提高函数的性能?

我正在使用的代码:

CREATE OR REPLACE FUNCTION ccdb_dummy.o_payments1(a integer)
  RETURNS void AS
$BODY$
DECLARE
cursor_1  refcursor;
cursor_2  refcursor;
rowcount integer;
rowcount1 integer;
payment_no bigint;
query_1 character varying(250);
lc_cin_num bigint;
test character varying(50);
t_payments ccdb_stg.o_payments_stg%ROWTYPE;
t_payments_details ccdb_stg.o_payment_head_dtls_stg%ROWTYPE;

BEGIN
rowcount := 0;

open cursor_1 for select * from ccdb_stg.o_payments_stg WHERE section_code = a;

select count(1) into rowcount from ccdb_stg.o_payments_stg WHERE section_code = a;

for i IN 1..rowcount loop

fetch cursor_1 into t_payments;

payment_no= nextval('ccdb_stg.payments_seq');

select cin into lc_cin_num from ccdb_dummy.consumers a where a.consumer_num =           t_payments.consumer_num;

insert into  ccdb_dummy.payments(payment_id,receipt_id,source_system_flag,cin,consumer_nbr,cust_connection_id,cust_type_flg,receipt_type_id,mop_code,mop_details,coll_effect_date,coll_entry_date,receipt_num,receipt_amt,receipt_loc_flg,receipt_date,cancel_flag,acc_type_id,cust_section_code,coll_section_code,remarks,pm_paydate,pm_amount,ref_transaction_id,creation_dt,created_by)    values(payment_no,t_payments.receipt_id,t_payments.origin_flag,lc_cin_num,t_payments.consumer_num,t_payments.cust_connection_id,t_payments.cust_type_flag,t_payments.receipt_type_id,t_payments.mop_id,t_payments.mop_details,t_payments.coll_effect_date,t_payments.coll_entry_date,t_payments.receipt_num,t_payments.receipt_amt,t_payments.receipt_flag,t_payments.receipt_date,t_payments.cancel_flag,t_payments.acc_type_flag,t_payments.cust_section_code,t_payments.coll_section_code,t_payments.remarks,t_payments.pm_paydate,t_payments.pm_amount,null,now(),'system');

select count(1) into rowcount1 from ccdb_stg.o_payment_head_dtls_stg a where a.mbc_receipt_id = t_payments.receipt_id;

open cursor_2 for select * from ccdb_stg.o_payment_head_dtls_stg a where a.mbc_receipt_id = t_payments.receipt_id;

for i IN 1..rowcount1 loop

fetch cursor_2 into t_payments_details;

insert into ccdb_dummy.payment_head_dtls(payment_id,mbc_receipt_id,charge_head_code,amount,tariff_id,creation_dt,created_by)
values (payment_no,t_payments_details.mbc_receipt_id,t_payments_details.charge_head_code,t_payments_details.amount,t_payments_details.tariff_id,now(),'system');

end loop;

close cursor_2;

end loop;

close cursor_1;

END;
$BODY$
  LANGUAGE plpgsql;

你的功能,从根本上简化:

CREATE OR REPLACE FUNCTION ccdb_dummy.o_payments1(a integer)
  RETURNS void
  LANGUAGE plpgsql AS
$func$
DECLARE
   t   record;
   t1  record;
BEGIN
   FOR t IN
      SELECT *
           , nextval('ccdb_stg.payments_seq') AS payment_no
           , c.cin
      FROM   ccdb_stg.o_payments_stg   p
      LEFT   JOIN ccdb_dummy.consumers c USING (consumer_num)
      WHERE  p.section_code = $1
   LOOP
      INSERT INTO ccdb_dummy.payments(payment_id,receipt_id,source_system_flag,cin, ... ,pm_amount,ref_transaction_id,creation_dt,created_by)
      VALUES(t.payment_no,t.receipt_id,t.origin_flag,t.cin, ... ,t.pm_amount,null,now(),'system');

      FOR t1 IN
         SELECT *
         FROM   ccdb_stg.o_payment_head_dtls_stg h
         WHERE  h.mbc_receipt_id = t.receipt_id
      LOOP
         INSERT INTO ccdb_dummy.payment_head_dtls(payment_id,mbc_receipt_id,charge_head_code,amount,tariff_id,creation_dt,created_by)
         VALUES (t.payment_no,t1.mbc_receipt_id,t1.charge_head_code,t1.amount,t1.tariff_id,now(),'system');
      END LOOP;
   END LOOP;
END
$func$;
  • 使用 a 的隐式游标FOR LOOP而不是笨重的显式游标加上冗余计数和循环。Much更简单、更快。阅读手册中的“循环查询结果”一章 https://www.postgresql.org/docs/current/plpgsql-control-structures.html#PLPGSQL-RECORDS-ITERATING.

  • LEFT JOIN to ccdb_dummy.consumers在第一个SELECT而不是为每一行运行单独的选择。

  • 还包括nextval('ccdb_stg.payments_seq') AS payment_no在第一个SELECT。比许多单独的查询便宜。

但这还远非完美。考虑一种全新的方法基于集合的操作而不是循环中的单独插入。但更干净、更快。这就是现代 RDBMS 的最佳运行方式。

One具有数据修改 CTE 的 SQL 语句

包装到 SQL 函数中以作为直接替换。
数据修改 CTE https://www.postgresql.org/docs/current/queries-with.html#QUERIES-WITH-MODIFYING需要 Postgres9.1或稍后。

CREATE OR REPLACE FUNCTION ccdb_dummy.o_payments2(integer)
  RETURNS void
  LANGUAGE sql AS
$func$
   WITH ins1 AS (
      INSERT INTO ccdb_dummy.payments(
             payment_id,                        cin,  receipt_id, ...  ,   pm_amount, ref_transaction_id,creation_dt,created_by)   
      SELECT nextval('ccdb_stg.payments_seq'),c.cin,p.receipt_id, ...  , p.pm_amount, null,              now(),      'system'
      FROM   ccdb_stg.o_payments_stg   p
      LEFT   JOIN ccdb_dummy.consumers c USING (consumer_num)
      WHERE  p.section_code = $1
      RETURNING payment_id, receipt_id
      )
   INSERT INTO ccdb_dummy.payment_head_dtls(
            payment_id,  mbc_receipt_id,  charge_head_code,  amount,  tariff_id,creation_dt,created_by)
   SELECT i.payment_id,h.mbc_receipt_id,h.charge_head_code,h.amount,h.tariff_id,now(),      'system'
   FROM   ins1 i
   JOIN   ccdb_stg.o_payment_head_dtls_stg h ON h.mbc_receipt_id = i.receipt_id;
$func$;

应该与上面的 plpgsql 函数完全相同(除非翻译错误)。只是更简单、更快.

在 SO 上查找使用数据修改 CTE 的 INSERT 的更多示例。 https://stackoverflow.com/search?q=%5Bpostgres%5D%20%22data-modifying%20CTE%22%20insert

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何提高 PostgreSQL 中带有游标的函数的性能? 的相关文章

随机推荐

  • 使用 LoadLibrary 在 .pyd 中加载 cython cdef 函数时出现问题

    我正在尝试在 C 中动态加载 cythonized pyd 在 Linux 机器中创建一个 so 文件 使用 so 我可以执行以下操作 plugin dlopen foo so RTLD LAZY init dlsym plugin PyI
  • 调试 Jersey 解组错误 - 错误请求语法不正确

    我正在 Glassfish 上的 Jersey 的帮助下构建 REST Web 服务 现在我正在为我的搜索查询的自定义输入源而苦苦挣扎 如果有搜索方法 POST Path search Consumes application xml ap
  • HSTS 预加载列表 - www 网站可能存在 SEO 问题

    让我在这里解释一下现实世界的情况 我运行网站https www liloo ro https www liloo ro我想为其启用 HSTS HSTS 预加载 问题是为了将其提交给预加载列表 https hstspreload org th
  • 无法制作固定大小数组的向量?

    我有这个奇怪的问题 vector
  • 更改 igraph 图中子图的颜色

    我有以下代码来绘制图的最小生成树 g is an igraph graph mst minimum spanning tree g E g color lt SkyBlue2 how to I make mst a different co
  • 无法访问用户控制组件[关闭]

    Closed 这个问题需要调试细节 help minimal reproducible example 目前不接受答案 在我的用户控件中 我有一个名为的 datagridviewdgvCustomers 我想在 gridview 中加载客户
  • 延长 R 中绘图轴的长度?

    如何在 R 中扩展轴线以覆盖数据范围 例如 在 我的数据大约为 2100 我希望 x 轴的线能走那么远 但不要在 2100 处做刻度线或标签 这在 R 中是否可能 这是用于制作上述绘图的代码 hist x breaks 50 xlab ma
  • 对python的LOAD_FAST/STORE_FAST感到困惑

    当我写一些代码时 我发现一个有趣的事情 def test l for i in range 10 def f pass print f l append f test import dis dis dis test 输出是
  • 如何从 pandas 邻接矩阵数据帧创建有向 networkx 图?

    我有一个以下形式的 pandas 数据框 df A B C D A 0 0 5 0 5 0 B 1 0 0 0 C 0 8 0 0 0 2 D 0 0 1 0 我正在尝试由此创建一个 networkx 图 我尝试过以下代码变体 A G ne
  • “cordova 平台添加 android”shasum 错误

    我正在完成设置和 HelloWorld 示例http cordova apache org docs en 3 5 0 guide cli index md html The 20Command Line 20Interface http
  • 当我导入 Xerces 库时无法构建应用程序(退出值 1)

    当我导入 Xerces 库时 我似乎无法构建我的应用程序 由于之前的问题 我已经在使用 multidex 因此我知道这一切都设置正确 我花了几天时间在网上查找并尝试各种版本的 Xerces 并对我的 build gradle 进行调整 但无
  • CSS open-quote 显示 1 个引号

    我使用以下 CSS 在段落前添加左引号 blockquote padding 22px quotes 201C 201D 2018 2019 font size 15px blockquote before color 111 conten
  • Postgres:整数范围的唯一约束

    给定两个整数 开始和结束 以及一个外键 我如何定义一个unique对区间 start end 和foreign key 的约束 鉴于我的表中有以下条目 start end foreign key 10 20 04ef8258 917c 46
  • Java中如何获取字符类型的类别名称?

    The Character getType int codePoint 返回一个整数 但我找不到方法 从中获取 unicode 类别名称 例如 Lu 或 Cn 我想要的是一种方法 例如Character getCategoryTypeNam
  • scala 中的构造函数(主/辅助/默认主)

    一个非常简单的练习凯霍斯特曼的 book Scala 适合不耐烦的人 一直让我困惑 是关于primary auxiliary and default primary构造函数 例如 5 10 考虑班级 class Employee val n
  • 不会采用父级
  • 我有一个 ul 与几个 li 其中的所有项目都在一行中 这 li li 有一个嵌套的 span and an img The img 所有项目的高度都相同 但是 span 项目包含可以跨越单行或两行的文本 取决于文本 我尝试过申请displ
  • ParseException:无效的会话令牌错误

    我做了一个简单的注册用户界面只是为了检查解析 但由于某种原因每次我尝试注册用户时都会出现此错误 这是代码 final ProgressDialog dlg new ProgressDialog this dlg setTitle Pleas
  • Java 中的内存映射集合

    我正在填满 JVM 堆空间 更改参数以为 JVM 提供更多堆空间 或更改代码中算法中的某些内容以不使用这么多空间是最推荐的两个选项 但是 如果这两个已经被尝试和应用 并且我仍然遇到内存不足的异常 我想看看其他选项是什么 我发现了这个例子 对
  • 使用 Keras (PIL) 和 TensorFlow 调整图像大小不一致?

    我对以下之间明显的不一致感到困扰 图像调整大小功能来自keras preprocessing 它们是 PIL 函数的包装器 TensorFlow 中的图像大小调整函数tf image 我正在使用 Keras 为计算机视觉任务训练深度学习模型
  • 如何提高 PostgreSQL 中带有游标的函数的性能?

    我有两个嵌套游标的功能 外部游标从源获取客户的付款详细信息 并根据某些业务逻辑插入到目标中 内部光标获取每笔付款的付款详细信息 它接连发生 Payments 表大约有 125000 行 其中大约 335000 行用于付款详细信息 所有这些行