記一次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表的緣由,並且一定能重現。
相關文章
相關標籤/搜索