使用存儲過程將Oracle數據批量導出爲多個csv文件

數據庫有如下表結構:

aaa ( 

        obj_id          NUMBER,  (Primary Key)

        obj_name   VARCHAR2(80),

        obj_size   NUMBER NOT NULL

        obj_time       NUMBER NOT NULL

        ms_version        NUMBER NOT NULL

)

現在有100萬條記錄,要求每1000條記錄導出爲一個csv文件,共計1000個文件,文件名稱格式爲output0.csv,output1.csv......output999.csv。

每個csv文件每行記錄包含:$1, $2, $3, $4四部分內容。

$1 = obj_id|obj_name

$2 = obj_size *10+obj_version

$3 = obj_time in format YYYY-MM-DD HH:mi

$4 = obj_name

要求第一個文件在500ms以內產生出來,後面每個文件生成間隔時間不得大於500ms,速度均勻。

方案一:使用pl/sql存儲過程分頁查詢,每次查詢1000條記錄寫一個文件,實現代碼如下:

[sql] view plain copy
  1. create or replace procedure export_to_csv(P_DIR IN VARCHAR2)  
  2. is  
  3. CSV_OUTPUT UTL_FILE.FILE_TYPE;  
  4. MAX_LINE NUMBER := 1000;  
  5. OUT_FILE_NAME varchar2(20);  
  6. OBJ_SIZE NUMBER;  
  7. MIN_RECORD NUMBER;  
  8. MAX_RECORD NUMBER;  
  9. OBJ_DATE varchar2(100);  
  10. BEGIN_TIME NUMBER;  
  11. END_TIME NUMBER;  
  12. begin  
  13.         BEGIN_TIME := dbms_utility.get_time;--記錄開始時間,注意dbms_utility.get_time獲取的時間戳單位是1/100s  
  14.         FOR I IN 0..999 loop  
  15.                 OUT_FILE_NAME := 'output' || I ||'.csv';--拼接文件名  
  16.                 MIN_RECORD := i*1000 + 1;--分頁查詢起始記錄  
  17.                 MAX_RECORD := (i+1)*1000;--分頁查詢中止記錄  
  18.                 --以寫方式打開指定目錄中指定文件名文件  
  19.                 CSV_OUTPUT := UTL_FILE.FOPEN(P_DIR, OUT_FILE_NAME, 'W', MAX_LINE);  
  20.             --隱式遊標,每次查詢1000條記錄  
  21.                 FOR cur IN (SELECT * FROM(SELECT A.*, ROWNUM rn FROM(SELECT * FROM aaa)A WHERE ROWNUM <= MAX_RECORD) WHERE rn >= MIN_RECORD) LOOP  
  22.                         OBJ_SIZE := cur.OBJ_SIZE*10 + cur.MS_VERSION;  
  23.             --將數值類型數據轉換爲日期字符串  
  24.                         OBJ_DATE := TO_CHAR(TO_DATE('19700101','yyyymmdd') + cur.OBJ_TIME/86400,'yyyy-MM-dd HH24:mi');  
  25.             --寫文件  
  26.                         UTL_FILE.PUT_LINE(CSV_OUTPUT,cur.OBJ_ID || '|' || cur.OBJ_NAME || ',' || OBJ_SIZE || ',' || OBJ_DATE || ',' || cur.OBJ_NAME);  
  27.                 END LOOP;  
  28.                 UTL_FILE.FCLOSE(CSV_OUTPUT);  
  29.         END LOOP;  
  30.         END_TIME := dbms_utility.get_time;  
  31.         DBMS_output.put_line('Total time=' || (END_TIME-BEGIN_TIME)*10 || 'ms.');  
  32. END;  
  33. /  
  34. begin  
  35. export_to_csv('MYDIR');  
  36. end;  
  37. /  

經過測試,1000個文件總共花150s,平均每個文件150ms。

注意:執行該存儲過程之前,UTL_FILE的目錄必須以sysdba的用戶創建,然後授權給使用的用戶,代碼中的MYDIR通過下面方法創建:

首先,以sysdba用戶登錄。

其次,創建目錄,如:CREATE DIRECTORY MYDIR AS 'c:\oraload\';

最後,給用戶授權,如:GRANT READ,WRITE ON DIRECTORY MYDIR TO scott;

方案二:部分頁,一次性將100萬條記錄全部查詢出來放到遊標中,每1000條寫一個文件,代碼如下:

[sql] view plain copy
  1. create or replace procedure export_to_csv(P_DIR IN VARCHAR2)  
  2. is  
  3. --顯示遊標,一次性將數據全部查詢完  
  4. cursor mycur is select * from aaa;  
  5. --行記錄  
  6. myrecord aaa%rowtype;  
  7. CSV_OUTPUT UTL_FILE.FILE_TYPE;  
  8. MAX_LINE NUMBER := 1000;  
  9. OUT_FILE_NAME varchar2(20);  
  10. OBJ_SIZE NUMBER;  
  11. OBJ_DATE varchar2(100);  
  12. BEGIN_TIME NUMBER;  
  13. END_TIME NUMBER;  
  14. COUNT_NUM NUMBER;  
  15. begin  
  16.         BEGIN_TIME := dbms_utility.get_time;  
  17.       --顯式打開遊標  
  18.         open mycur;  
  19.         FOR I IN 0..999 loop  
  20.             --拼接文件名  
  21.                 OUT_FILE_NAME := 'output' || I ||'.csv';  
  22.                 COUNT_NUM := 0;  
  23.                 --打開文件  
  24.                 CSV_OUTPUT := UTL_FILE.FOPEN(P_DIR, OUT_FILE_NAME, 'W', MAX_LINE);   
  25.             --每1000條寫一個文件  
  26.                 while COUNT_NUM < 1000 loop  
  27.                   --逐條叫遊標記錄放入記錄中  
  28.                         fetch mycur into myrecord;  
  29.                         OBJ_SIZE := myrecord.OBJ_SIZE*10 + myrecord.MS_VERSION;  
  30.                         OBJ_DATE := TO_CHAR(TO_DATE('19700101','yyyymmdd') + myrecord.OBJ_TIME/86400,'yyyy-MM-dd HH24:mi');  
  31.                         UTL_FILE.PUT_LINE(CSV_OUTPUT,myrecord.OBJ_ID || '|' || myrecord.OBJ_NAME || ',' || OBJ_SIZE || ',' || OBJ_DATE || ',' || myrecord.OBJ_NAME);  
  32.                 COUNT_NUM := COUNT_NUM+1;  
  33.             --取遊標中下一條記錄  
  34.                 fetch mycur into myrecord;  
  35.                 END LOOP;  
  36.                 UTL_FILE.FCLOSE(CSV_OUTPUT);  
  37.         END LOOP;  
  38.       --關閉遊標  
  39.         close mycur;  
  40.         END_TIME := dbms_utility.get_time;  
  41.         DBMS_output.put_line('Total time=' || (END_TIME-BEGIN_TIME)*10 || 'ms.');  
  42. END;  
  43. /  
  44. begin  
  45. export_to_csv('MYDIR');  
  46. end;  
  47. /  
經測試發現,100萬條記錄總共耗時50s,平均每個文件50ms,速度大大提高。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章