1. 程式人生 > >oracle一段SQL引發的血案。。。。

oracle一段SQL引發的血案。。。。

今天有個複雜的SQL,我對oralce就是一個小白。。。 需求為:需要將execl的資料匯入到一張temp表,然後從temp表中查出所有的資料分別匯入到兩張表中,但是這兩張表分別為主副表,主表必須先插,才能插副表。 我的SQL在38萬條資料的基礎上,需要16個小時。。。。呵呵噠。。真特麼慢。。 但是同事的只用了1分鐘多點。。。 算是學習了,記錄一下 於是乎我的SQL如下:

--先刪除索引
------------
declare
  v_cnt number(8):= 0;
	v_seq int := 0;
begin
  while v_cnt < 324271 loop
	--v_seq := SELECT SEQ_T_SH_CREADIT_PLM7020.nextval;
	select  SEQ_T_SH_CREADIT_PLM7020.nextval into v_seq  from  dual;
	INSERT INTO T_SH_CREADIT_PLM7020 (
		ID,
		ID_NUM,
		CUST_NAME,
		CELL_PHONE,
		APP_NUM,
		APP_DATE,
		APP_FLAG,
		FRD_PRODUCT_NUM,
		APP_PRODUCT_NUM,
		TRANSFER_ORG_NUM,
		APP_REASOM,
		FRD_DATA_NUM,
		ID_TYPE,
		REPAY_DATE,
		QUERY_STATE,
		CREATE_TIME,
		UPDATE_TIME
		) SELECT
		v_seq,
		SS.ID_NUM,
		SS.CUST_NAME,
		SS.CELL_PHONE,
		SS.APP_NUM,
		SS.APP_DATE,
		'1',
		'PLM7020',
		'A01',
		'TRA000',
		'R3',
		'1',
		'0',
		'1',
		'1',--已查詢
		SYSDATE,
		SYSDATE 
		FROM
			(
		SELECT ROWNUM
			rn,
			t.ID_NUM,
			t.CUST_NAME,
			t.CELL_PHONE,
			t.APP_NUM,
			t.APP_DATE
		FROM
			T_TMP_CREDIT_PLM7020 t 
		WHERE
			t.TERM_NUM = '1'
			) SS 
		WHERE
			rn > v_cnt
			AND rn <= v_cnt+1;
	--插入result表 SEQ_T_SH_PLM7020_RESULT.nextval, v_seq,
	INSERT INTO T_SH_CREADIT_PLM7020_RESULT (
		"ID",
		"USER_PLM7020_ID",
		"APP_DATE",
		"APP_NO",
		"APP_STATUS",
		"APP_VALID",
		"ERR_MSG",
		"APP_WARN",
		"DATA_STATUS",
		"DATA_VALID",
		"DATA_ERR_MSG",
		"PD1",
		"PD8",
		"PD22",
		"PD26",
		"PD29",
		"PD30",
		"PD36",
		"PD43",
		"PD45",
		"PD57",
		"PD59",
		"PD64",
		"PD66",
		"PD84",
		"PD86",
		"PD106",
		"PD111",
		"PD117",
		"PD122",
		"PD123",
		"PD139",
		"PD144",
		"PD161",
		"PD166",
		"PD167",
		"PD172",
		"PD177",
		"PD178",
		"PD379",
		"PD381",
		"PD383",
		"PD384",
		"PD385",
		"PD386",
		"PD387",
		"PD399",
		"PD400",
		"PD401",
		"PD402",
		"PD411",
		"ORI_JSON",
		"CREATE_TIME",
		"UPDATE_TIME" 
	) SELECT
	SEQ_T_SH_PLM7020_RESULT.nextval,
	v_seq,
	SS.APP_DATE,
	SS.APP_NUM,
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	SS.PD1,
	SS.PD8,
	SS.PD22,
	SS.PD26,
	SS.PD29,
	SS.PD30,
	SS.PD36,
	SS.PD43,
	SS.PD45,
	SS.PD57,
	SS.PD59,
	SS.PD64,
	SS.PD66,
	SS.PD84,
	SS.PD86,
	SS.PD106,
	SS.PD111,
	SS.PD117,
	SS.PD122,
	SS.PD123,
	SS.PD139,
	SS.PD144,
	SS.PD161,
	SS.PD166,
	SS.PD167,
	SS.PD172,
	SS.PD177,
	SS.PD178,
	SS.PD379,
	SS.PD381,
	SS.PD383,
	SS.PD384,
	SS.PD385,
	SS.PD386,
	SS.PD387,
	SS.PD399,
	SS.PD400,
	SS.PD401,
	SS.PD402,
	SS.PD411,
	'null',
	SYSDATE,
	SYSDATE 
	FROM
		(
		SELECT ROWNUM
			rn,
			t.APP_DATE,
			t.APP_NUM,
			t.PD1,
			t.PD8,
			t.PD22,
			t.PD26,
			t.PD29,
			t.PD30,
			t.PD36,
			t.PD43,
			t.PD45,
			t.PD57,
			t.PD59,
			t.PD64,
			t.PD66,
			t.PD84,
			t.PD86,
			t.PD106,
			t.PD111,
			t.PD117,
			t.PD122,
			t.PD123,
			t.PD139,
			t.PD144,
			t.PD161,
			t.PD166,
			t.PD167,
			t.PD172,
			t.PD177,
			t.PD178,
			t.PD379,
			t.PD381,
			t.PD383,
			t.PD384,
			t.PD385,
			t.PD386,
			t.PD387,
			t.PD399,
			t.PD400,
			t.PD401,
			t.PD402,
			t.PD411 
		FROM
			T_TMP_CREDIT_PLM7020 t 
		WHERE
			t.TERM_NUM = '1' 
		) SS 
	WHERE
		rn > v_cnt 
		AND rn <= v_cnt + 1;
--判斷是否提交 1000條一次commit
if MOD(v_cnt, 1000)=0 THEN
 if (v_cnt/1000)>=1 THEN
	commit;
 END if;
END IF;
--迴圈增加
	v_cnt := v_cnt+1;
  end loop; 
  commit;
end;

同事寫的程式碼使用了自定義型別和遊標,程式碼如下:

declare
  v_cnt number(8):= 0;
  v_plm7020_pk NUMBER;
  
  -- 每次檢索1000條
  RECORDS_PER_LOOP CONSTANT NUMBER(10) := 1000;
  
  -- 宣告新的型別
  TYPE PLM7020_LIST_TYPE IS TABLE OF t_tmp_credit_PLM7020%ROWTYPE INDEX BY BINARY_INTEGER;
  
  v_PLM7020_LIST PLM7020_LIST_TYPE;
  v_PLM7020_LIST_ROW T_TMP_CREDIT_PLM7020%rowtype;
  
  -- 查詢批次號是20181102001,且未處理的資料
  cursor cur_PLM7020_LIST is
    select * from t_tmp_credit_PLM7020 t1
    where t1.status = 0
    and t1.batch_num = '20181102001';
  
begin
  -- 開啟遊標
  OPEN cur_PLM7020_LIST;
  
  LOOP
    fetch cur_PLM7020_LIST BULK COLLECT 
      INTO v_PLM7020_LIST limit RECORDS_PER_LOOP;
    
    -- 如果集合有資料
    IF v_PLM7020_LIST.COUNT > 0 THEN
      -- 迴圈插入到算話結果表
      FOR i IN v_PLM7020_LIST.FIRST .. v_PLM7020_LIST.LAST LOOP
        v_PLM7020_LIST_ROW := v_PLM7020_LIST(i);
        
        -- 獲取SEQ_T_SH_CREADIT_PLM7020主鍵
        select SEQ_T_SH_CREADIT_PLM7020.nextval 
          into v_plm7020_pk  
        from dual;
  
        INSERT INTO T_SH_CREADIT_PLM7020 (
          ID,
          ID_NUM,
          CUST_NAME,
          CELL_PHONE,
          APP_NUM,
          APP_DATE,
          APP_FLAG,
          FRD_PRODUCT_NUM,
          APP_PRODUCT_NUM,
          TRANSFER_ORG_NUM,
          APP_REASOM,
          FRD_DATA_NUM,
          ID_TYPE,
          REPAY_DATE,
          QUERY_STATE,
          CREATE_TIME,
          UPDATE_TIME
        ) VALUES(
          v_plm7020_pk,
          v_PLM7020_LIST_ROW.ID_NUM,
          v_PLM7020_LIST_ROW.CUST_NAME,
          v_PLM7020_LIST_ROW.CELL_PHONE,
          v_PLM7020_LIST_ROW.APP_NUM,
          v_PLM7020_LIST_ROW.APP_DATE,
          '1',
          'PLM7020',
          'A01',
          'TRA000',
          'R3',
          '1',
          '0',
          '1', --幾號端
          '1',--已查詢
          SYSDATE,
          SYSDATE 
        );
  
        --插入result表 SEQ_T_SH_PLM7020_RESULT.nextval, v_seq,
        INSERT INTO T_SH_CREADIT_PLM7020_RESULT (
          ID,
          USER_PLM7020_ID,
          APP_DATE,
          APP_NO,
          APP_STATUS,
          APP_VALID,
          ERR_MSG,
          APP_WARN,
          DATA_STATUS,
          DATA_VALID,
          DATA_ERR_MSG,
          PD1,
          PD8,
          PD22,
          PD26,
          PD29,
          PD30,
          PD36,
          PD43,
          PD45,
          PD57,
          PD59,
          PD64,
          PD66,
          PD84,
          PD86,
          PD106,
          PD111,
          PD117,
          PD122,
          PD123,
          PD139,
          PD144,
          PD161,
          PD166,
          PD167,
          PD172,
          PD177,
          PD178,
          PD379,
          PD381,
          PD383,
          PD384,
          PD385,
          PD386,
          PD387,
          PD399,
          PD400,
          PD401,
          PD402,
          PD411,
          ORI_JSON,
          CREATE_TIME,
          UPDATE_TIME 
        ) values (
          SEQ_T_SH_PLM7020_RESULT.nextval,
          v_plm7020_pk,
          v_PLM7020_LIST_ROW.APP_DATE,
          v_PLM7020_LIST_ROW.APP_NUM,
          '',
          '',
          '',
          '',
          '',
          '',
          '',
          v_PLM7020_LIST_ROW.PD1,
          v_PLM7020_LIST_ROW.PD8,
          v_PLM7020_LIST_ROW.PD22,
          v_PLM7020_LIST_ROW.PD26,
          v_PLM7020_LIST_ROW.PD29,
          v_PLM7020_LIST_ROW.PD30,
          v_PLM7020_LIST_ROW.PD36,
          v_PLM7020_LIST_ROW.PD43,
          v_PLM7020_LIST_ROW.PD45,
          v_PLM7020_LIST_ROW.PD57,
          v_PLM7020_LIST_ROW.PD59,
          v_PLM7020_LIST_ROW.PD64,
          v_PLM7020_LIST_ROW.PD66,
          v_PLM7020_LIST_ROW.PD84,
          v_PLM7020_LIST_ROW.PD86,
          v_PLM7020_LIST_ROW.PD106,
          v_PLM7020_LIST_ROW.PD111,
          v_PLM7020_LIST_ROW.PD117,
          v_PLM7020_LIST_ROW.PD122,
          v_PLM7020_LIST_ROW.PD123,
          v_PLM7020_LIST_ROW.PD139,
          v_PLM7020_LIST_ROW.PD144,
          v_PLM7020_LIST_ROW.PD161,
          v_PLM7020_LIST_ROW.PD166,
          v_PLM7020_LIST_ROW.PD167,
          v_PLM7020_LIST_ROW.PD172,
          v_PLM7020_LIST_ROW.PD177,
          v_PLM7020_LIST_ROW.PD178,
          v_PLM7020_LIST_ROW.PD379,
          v_PLM7020_LIST_ROW.PD381,
          v_PLM7020_LIST_ROW.PD383,
          v_PLM7020_LIST_ROW.PD384,
          v_PLM7020_LIST_ROW.PD385,
          v_PLM7020_LIST_ROW.PD386,
          v_PLM7020_LIST_ROW.PD387,
          v_PLM7020_LIST_ROW.PD399,
          v_PLM7020_LIST_ROW.PD400,
          v_PLM7020_LIST_ROW.PD401,
          v_PLM7020_LIST_ROW.PD402,
          v_PLM7020_LIST_ROW.PD411,
          'offline',
          SYSDATE,
          SYSDATE 
        );
        
        v_cnt :=v_cnt + 1;
        
      END LOOP;
      COMMIT;
    END IF;
    -- 清空列表 v_PLM7020_LIST
    v_PLM7020_LIST.delete;
    -- 如果遊標檢索不到資料,則退出迴圈
    EXIT WHEN cur_PLM7020_LIST%NOTFOUND;
  END LOOP;
  
  -- 統計插入了多少行
  dbms_output.put_line('插入資料行數:' || v_cnt);
      
  -- 關閉遊標
  CLOSE cur_PLM7020_LIST;
  
  EXCEPTION
      WHEN OTHERS THEN
      rollback;
      dbms_output.put_line('執行出錯');
end;