1. 程式人生 > >記一次postgresql數據庫函數執行問題

記一次postgresql數據庫函數執行問題

absolute btree 服務器 -m ans ica ret cpu integer



一、函數說明:

首先編寫了三個函數:func_init.sqlfunc_process.sqlfunc_uuid.sql

1、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;
...
12 1
...
2
BEGIN
3
4
FOR i IN 1..num LOOP
5
6
    SELECT func_process.sql() INTO counts;
7
8
    if counts = 0 then return ‘mac地址已使用完‘;
9
    end if;
10
11
end LOOP;
12
...

2、func_process.sql 沒有入參,出參為完成狀態值integer,裏面共分五步: a)、查詢macInfo表,得到一條state=0的mac值【該表有65w條數據,且只有mac和state兩個字段,mac為主鍵】
select mac from macInfo where state = 0 limit 1;
1 1
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。

3、func_uuid.sql通過plpythonu語言編寫,生成UUID,與sql無關。


二、postgresql函數問題:

單個函數就是一個事物,無法主動提交事物。也就是說,我func_init傳入的值是多少,那麽必須這些全部處理完才會提交事務,中途無法主動提交。

三、前提如下:

由於一開始沒有特別的考慮性能問題,使用了insert into,而不是copy。macInfo表裏state沒有建立索引。一開始macInfo表的所有state都為0。寫了一個python腳本,在服務器循環調用func_init(10000),調用了65次,用來規避postgresql無法主動提交事務問題。

四、發生的問題以及排查

1、一開始跑的時候,前幾次func_init(10000),也就是執行10000次func_process,耗時135s。func_init(10000)跑到第60次的時候,發現耗時非常久,需要20分鐘多。也就是速度慢了10倍。
檢查postgresql所在服務器,發現當執行函數的時候,會將一個cpu占到90%,占所有cpu的6%。當這個函數執行完成時,幾乎不占,因此可以確定是這個函數造成的。
2、經過排除,發現是第a步,查詢mac非常慢,每次耗時100ms。原本耗時是7ms。
猜想macInfo表中state當時值分布中為0的已經很少,都是為1的,且沒有索引導致查詢慢。
>> select "state", "count"("state") from macinfo GROUP BY state;
>> 
state count
1	641153
0	15000
5 1
>> select "state", "count"("state") from macinfo GROUP BY state;
2
>> 
3
state count
4
1   641153
5
0   15000
3、因此為state加上索引。
CREATE INDEX "idx_macinfo_state" ON "usr"."macinfo" USING BTREE ("state");
1 1
CREATE INDEX "idx_macinfo_state" ON "usr"."macinfo" USING BTREE ("state");
4、再次執行,發現速度還是很慢,幾乎沒有改變。
5、既然索引沒用,那麽我刪掉state為1的數據,只留下15000條state為0的數據。
create table usr.macinfo_copy as select * from usr.macinfo;
DELETE FROM usr.macinfo where "state" <> 0;
1 1
create table usr.macinfo_copy as select * from usr.macinfo;
2
DELETE FROM usr.macinfo where "state" <> 0;
6、再次執行,本次執行了1000條,發現耗時680s,換算成10000條也就是 10分鐘多點。相比快了一倍,但是和最開始比還是慢了5倍。因此該方法還是不行
7、還原macinfo表,將數據還原成最初形式。再次執行。速度還是很慢,1000條500s。
五、小結發現就是macinfo表的原因,而且必定能重現。

記一次postgresql數據庫函數執行問題