2017-11-16 8 views
1

내가 가지고있는 소스 테이블에 ;에 의해 구문 분석 값으로 테이블 웁니다 INSERT INTO SELECT 문 : 그래서오라클 SQLDeveloper에 REGEXP 레벨 쿼리 속도를하는 방법

INSERT INTO PC_MATERIALS_BRIDGE (MATERIAL_BRIDGE_ID, VARIABLE_ID, MATERIAL_NAME) 
    SELECT PC_VAR_MATERIALS_BRIDGE_SEQ.NEXTVAL, VARIABLE_ID, MATERIAL_NAME FROM (SELECT DISTINCT E.VARIABLE_ID, LOWER(TRIM(REGEXP_SUBSTR(e.MATERIALS, '[^;]+', 1, LEVEL))) MATERIAL_NAME 
     FROM (SELECT VARIABLE_ID, MATERIALS FROM SRC_VARS_OCEAN_ALL WHERE MATERIALS IS NOT NULL AND MATERIALS != 'N/A) e 
     CONNECT BY LOWER(TRIM(REGEXP_SUBSTR(e.MATERIALS, '[^;]+', 1, LEVEL))) IS NOT NULL); 

을, 소스 테이블의 데이터

ID  MATERIAL_NAME 
1  paper 
2  paper; plastic 
대상 테이블

같은
MATERIAL_BRIDGE_ID  MATERIAL_NAME 
1      paper 
2      paper 
3      plastic 

나타날 것이다.

스크립트가 정상적으로 실행됩니다. 그러나 원본 테이블의 레코드가 거의 40,000 개이고 일부 레코드의 값이 3 개 (예 : paper; plastic; rubber)이므로 많은 비용이 듭니다. 나는 LEVEL이 비싸다는 것을 안다. 나는 MATERIAL_NAMEVARCHAR2(255 BYTE)으로 설정했습니다. 다른 유형의 검색어를 작성하는 것 이외의 개선 방법 (예 : 재귀 적이지만 문제가있을 수 있음)을 잘 모릅니다. DISTINCT도 느려지는 원인입니까? e.VARIABLE_ID이 이제 기본 키이므로 DISTINCT은 더 이상 필요하지 않을 수도 있습니다.

답변

2

이것은 매우 비효율적 인 방법입니다.

create table SRC_VARS_OCEAN_ALL(
    VARIABLE_ID int, 
    MATERIALS varchar2(200) 
); 

insert into SRC_VARS_OCEAN_ALL values(1, 'ala;ma;kota'); 
insert into SRC_VARS_OCEAN_ALL values(2, 'as;to;pies'); 
insert into SRC_VARS_OCEAN_ALL values(3, 'baba;jaga'); 
insert into SRC_VARS_OCEAN_ALL values(4, 'zupa;obiad'); 

과 :이 쿼리는 4 개의 입력 행에 대한 (52)의 출력 기록을 생성

SELECT E.VARIABLE_ID, level, 
     LOWER(TRIM(REGEXP_SUBSTR(e.MATERIALS, '[^;]+', 1, LEVEL))) MATERIAL_NAME 
FROM (
    SELECT VARIABLE_ID, MATERIALS 
    FROM SRC_VARS_OCEAN_ALL 
    WHERE MATERIALS IS NOT NULL 
    AND MATERIALS != 'N/A' 
) e 
CONNECT BY LOWER(TRIM(REGEXP_SUBSTR(e.MATERIALS, '[^;]+', 1, LEVEL))) IS NOT NULL 
order by 1,2; 

VARIABLE_ID  LEVEL MATERIAL_NAME  
----------- ---------- ----------------- 
      1   1 ala    
      1   2 ma     
      1   2 ma     
      1   2 ma     
      1   2 ma     
      1   3 kota    
      1   3 kota    
      1   3 kota    
      1   3 kota    
      1   3 kota    
      1   3 kota    
      1   3 kota    
      1   3 kota    
      1   3 kota    
      1   3 kota    
      1   3 kota    
      1   3 kota    
      1   3 kota    
      1   3 kota    
      1   3 kota    
      1   3 kota    
      2   1 as     
      2   2 to     
      2   2 to     
      2   2 to     
      2   2 to     
      2   3 pies    
      2   3 pies    
      2   3 pies    
      2   3 pies    
      2   3 pies    
      2   3 pies    
      2   3 pies    
      2   3 pies    
      2   3 pies    
      2   3 pies    
      2   3 pies    
      2   3 pies    
      2   3 pies    
      2   3 pies    
      2   3 pies    
      2   3 pies    
      3   1 baba    
      3   2 jaga    
      3   2 jaga    
      3   2 jaga    
      3   2 jaga    
      4   1 zupa    
      4   2 obiad    
      4   2 obiad    
      4   2 obiad    
      4   2 obiad    

52 rows selected. 

이 문제가 발생하는 이유 당신은 당신이 아래의 간단한 데모에서 DISTINCT 제거 할 때 관찰 할 수있다 10 값. 얼마나 많은 사람들이 4 만명이 될지 짐작할 수 있습니다.
쿼리는 수백 개의 수천 또는 심지어 수백 개의 행을 생성 한 다음 DISTINCT는이 거대한 결과 집합을 정렬하여 중복을 제거합니다.

SELECT a.VARIABLE_ID, b.lev_el, 
     trim(regexp_substr(a.MATERIALS, '[^;]+', 1, b.lev_el)) as MATERIAL_NAME 
FROM SRC_VARS_OCEAN_ALL a 
JOIN (
    SELECT level as lev_el 
    FROM dual CONNECT BY level <= 100 
) b 
ON b.lev_el <= regexp_count(a.MATERIALS, ';') + 1 

VARIABLE_ID  LEV_EL MATERIAL_NAME 
----------- ---------- -------------- 
      1   1 ala   
      2   1 as    
      3   1 baba   
      4   1 zupa   
      1   2 ma    
      2   2 to    
      3   2 jaga   
      4   2 obiad   
      1   3 kota   
      2   3 pies   

10 rows selected. 

내가 assumming하고 더 있다는 것을 : 그것은 단지 10 개의 레코드, 더 이상 이하, 단지만큼이 작업을 수행 할 필요를 생성하기 때문에


아래 쿼리는 훨씬 더 수행해야 각 목록에는 100 개가 넘는 값이 있습니다 (각 행에는 값이 100 개 이하인 목록이 있으므로) FROM dual CONNECT BY level <= 100 절이 있습니다.

+0

대단히 감사합니다. 나는 DISTINCT를 사용했지만 모든 가능한 행을 검색 한 후에 행을 정렬한다는 사실을 간과했다. 건배. – snl330