记一次postgresql数据库函数执行问题

 
 

1、函数说明:

首先编写了三个函数:
func_init.sql
func_ process.sql
func_uuid.sql
 
 
一、func_init.sql 入参为一个int类型number,根据传入的number作循环,循环调用 func_ process.sql。
...
BEGIN

FOR i IN 1..num LOOP

    SELECT func_process.sql() INTO counts;

    if counts = 0 then return 'mac地址已使用完';
    end if;

end LOOP;
...

 

 
二、 func_ process.sql 没有入参,出参为完成状态值integer,里面共分五步:
    a)、查询macInfo表,获得一条state=0的mac值【该表有65w条数据,且只有mac和state两个字段,mac为主键】
select mac from macInfo where state = 0 limit 1;

 

    b)、调用func_uuid.sql,获得uuid【该方法经过plpythonu语言编写,生成UUID】
    c)、生成各个sequence(大概12个)
    d)、组装12个insert语句(12张表)【这里用到了第a步里获得的mac】
    e)、更新macInfo表,将mac值对应的数据的state改成1。
 
三、func_uuid.sql
经过plpythonu语言编写,生成UUID,与sql无关。
 
 

2、postgresql函数问题:

单个函数就是一个事物,没法主动提交事物。
也就是说,我func_init传入的值是多少,那么必须这些所有处理完才会提交事务,中途没法主动提交。
 

3、前提以下:

因为一开始没有特别的考虑性能问题,使用了insert into,而不是copy。
macInfo表里state没有创建索引。
一开始macInfo表的全部state都为0。
写了一个python脚本,在服务器循环调用func_init(10000),调用了65次,用来规避postgresql没法主动提交事务问题。
 

4、发生的问题以及排查

一、一开始跑的时候,
前几回func_init(10000),也就是执行10000次 func_ process,耗时135s。
func_init(10000)跑到第60次的时候,发现耗时很是久,须要20分钟多。
也就是速度慢了10倍。
 
检查postgresql所在服务器,发现当执行函数的时候,会将一个cpu占到90%,占全部cpu的6%。
当这个函数执行完成时,几乎不占,所以能够肯定是这个函数形成的。
 
二、通过排除,发现是第a步,查询mac很是慢,每次耗时100ms。本来耗时是7ms。
猜测macInfo表中state当时值分布中为0的已经不多,都是为1的,且没有索引致使查询慢。
>> select "state", "count"("state") from macinfo GROUP BY state;
>> 
state count
1    641153
0    15000

 

 

三、所以为state加上索引。
CREATE INDEX "idx_macinfo_state" ON "usr"."macinfo" USING BTREE ("state");

 

四、再次执行,发现速度仍是很慢,几乎没有改变。
五、既然索引没用,那么我删掉state为1的数据,只留下15000条state为0的数据。
create table usr.macinfo_copy as select * from usr.macinfo;
DELETE FROM usr.macinfo where "state" <> 0;

 

六、再次执行,本次执行了1000条,发现耗时680s,换算成10000条也就是 10分钟多点。
相比快了一倍,可是和最开始比仍是慢了5倍。所以该方法仍是不行
 
七、还原macinfo表,将数据还原成最初形式。再次执行。速度仍是很慢,1000条500s。
 
5、小结
发现就是macinfo表的缘由,并且一定能重现。
相关文章
相关标签/搜索