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表的緣由,並且一定能重現。