2014-12-05 2 views
1

Date, Area, LocnID, ATTR1, ATTR2, ... ATTR10 열을 포함하는 서버 이름이 IOA.HAVE 인 일일 업데이트 데이터 세트가 있습니다. 단순히 문제로의 모든 특정 Date를 들어SAS의 다른 테이블에서 테이블 업데이트

Date Area LocnID A1 A2 
01Nov14 AAA 100000 50 G 
01Nov14 AAA 100001 30 G 
01Nov14 AAA 100002 30 K 
01Nov14 BBB 100003 20 K 
02Nov14 CCC 100009 30 C 
02Nov14 AAA 100000 50 G 

, LocnID이 고유 가정 해 봅시다.

Adjustment이라는 로컬 파일 (.xlxs)은 매일 proc import을 통해 SAS로 가져옵니다.

Date Area LocnID A1 A2 Type 
02Nov14 BBB 100000 50 G change 
02Nov14 CCC 100009 30 C close 
03Nov14 DDD 200000 20 open 

그 열은 Type 제외 HAVE에서와 유사하다.

Type = change 경우는 그 날에서 쳐다보고 의미의 LocnIDHAVE의 모든 속성은 Adjustment의 사람들에 의해 교체해야합니다. Type = close 인 경우 그날부터 LocnID이있는 모든 레코드는 HAVE에서 삭제해야합니다. Type = open 인 경우 해당 날짜부터 쳐다보고 HAVE에 새 레코드를 추가하십시오.

그래서 조정 후 IOA.HAVE

Date Area LocnID A1 A2 
01Nov14 AAA 100000 50 G 
01Nov14 AAA 100001 30 G 
01Nov14 AAA 100002 30 K 
01Nov14 BBB 100003 20 K 
02Nov14 BBB 100000 50 G /* change Area */ 
.... 
.... 
03Nov14 DDD 200000 20  /* open */ 

은 현재 내가이

data t1 t2; 
set adjustment; 
if type in ('change','close') then output t1; 
if type in ('change','open') then output t2; 
run; 

proc sql; 
create table a1 as 
select * from `IOA.HAVE1 as a 
where not exists (select * from work.t1 where a.Date >= t1.Date and a.LocnID = t1.LocnID) 
union 
select * from t2 
where t2.Date <= today() 
order by Date, LocnID; 
quit; 

처럼 그것을 그러나 이것은 매우 비효율적이다이어야한다. 이 방법을 최적화하는 방법 ('SQL'대신 'SAS'방식으로하는 것이 더 효과적입니까?)

+0

http://ftp.sas.com /techsup/download/observations/obswww19/obswww19.pdf에서 필요한 항목을 찾을 수 있습니다. – mjsqu

답변

2

테이블이 모두 date locnID으로 정렬 된 경우 잘못된 방법이 아닙니다. join 쿼리를 join으로 변경하는 것을 고려해 볼 수는 있지만, SQL은 하루 만에 같은 쿼리로 쿼리를 최적화해야한다고 생각합니다. 나는 이것을 추가/업데이트/삭제 트랜잭션을 수행하는 상당히 표준적인 방법이라고 말하고 싶다 : delete (update + delete), insert (update + add). 실제로 삭제 작업을 수행하는 것이 테이블을 다시 작성하는 것보다 효율적입니다.

흥미롭게도 색인을 추가하는 것은 입니다.이 검색어는입니다. 매우 잘못되었습니다. 인덱스없이 정렬 된 테이블에 대한 쿼리를 실행 한 결과 ~ 30 초 (테이블 크기 ~ 500k 가지, 조정할 때 ~ 1k). 색인으로 3 분. 문제는보다 큰 날짜입니다. 인덱스와 함께 사용하면 매우 나 빠지고 이와 같이 쿼리를 아프게하는 인덱스는 매우 일반적입니다.

SAS에서는 MERGE를 사용하여 쉽게이 작업을 수행 할 수 있습니다. MODIFY 문에서 복제하기 어려운 몇 가지 작업을 수행하기 때문에 MODIFY가 올바른 경로라고 생각하지 않습니다. 작동 할 수도 있지만 여기서 코드를 작성하는 것이 더 쉽습니다.

여기 예가 나와 있습니다. 아래에 SQL 코드를 비교 결과로 포함합니다. 하나의 큰 차이점이 있습니다. 내 SAS 코드에서 변경 사항을 삭제하지 않습니다. 즉, 나보다 많은 행을 가져옵니다. 변경 후 모든 행이 삭제됩니다. 당신은 SAS 방법에서도 그렇게 할 수 있지만 영어 버전의 스펙은 실제로 원하지 않는 것처럼 들립니다.

먼저 테스트 할 테이블을 만듭니다. 이것은 HAVE에있는 약 50 만 행과 천 조정입니다. 당신은 아마 더 많은 것을 가지고 있거나 물어 보지 않을 것입니다, 그러나 이것은 속도에 대한 아이디어를 줄 것입니다.

data have; 
    array locnIDs[1000] _Temporary_; 
    do _t = 1 to dim(locnIDs); 
    locnIDs[_t] = 1; 
    end; 
    call streaminit(7); 
    do date = '01NOV2011'd to '01DEC2014'd; 
    do _t = 1 to dim(locnIDs); 
     if rand('Uniform') < 0.02 then locnIDs[_t]=not(locnIDs[_t]); 
     if locnIDs[_t] then do; 
     locnID = 100000+_t; 
     A1=2**_t; 
     A2=byte(mod(_t,26)+65); 
     Area = repeat(byte(mod(_t,26)+65),2); 
     output; 
     end; 
    end; 
    end; 
run; 

data adjustment; 
    call streaminit(7); 
    set have; 
    by date locnID; 
    length type $6; 
    retain lastlocnID; 
    if (first.date) then lastlocnID=.; 
    if lastlocnID gt 0 and locnID-lastlocnID gt 1 then do; 
    if rand('Uniform') lt 0.001 then do;  
     locnID=locnID-1; 
     type='open'; 
     output; 
    end; 
    else if rand('Uniform') lt 0.001 then do; 
     type='close'; 
     output; 
    end; 
    end; 
    else do; 
    if rand('Uniform') lt 0.001 then do; 
     type='change'; 
     Area = '###'; 
     output; 
    end; 
    end; 
    lastlocnID=locnID; 
run; 

다음으로 나는 t1/t2로 분할하고 위에있는 SQL 메소드를 수행합니다.

data t1 t2; 
    set adjustment; 
    if type in ('change','close') then output t1; *t1 is changes/deletes; 
    if type in ('change','open') then output t2; *t2 is all adds/changes; 
run; 
proc sql; 
create table a1 as 
    select * from HAVE as a 
    where not exists (select * from work.t1 where a.Date >= t1.Date and a.LocnID = t1.LocnID) 
    union 
    select * from t2 
    where t2.Date <= today() 
    order by Date, LocnID; 
quit; 

이제 SAS 병합이 훨씬 빨라졌습니다. 기본적으로 나는 by locnid date을 정렬하여 변경 사항을 날짜 전체의 위치에 전파 한 다음 임시 저장 변수를 사용하여 전파해야하는 변경 값을 저장하고 삭제할 항목을 식별합니다. 변경 사항을 전파하고 나중에 변경된 모든 레코드를 삭제하지 않기 때문에 더 많은 레코드가 존재합니다. 당신이 그들을 삭제하려면이 방법은 여전히 ​​훨씬 쉽게 (당신이 출력 문 후 __delflag = 1을 물건 된 a1 __a1 = A1과 A1 = __을 모두 생략하고 할당 할 수 있습니다.)되어 있지만 작동

proc sort data=have; 
    by locnid date; 
run; 

proc sort data=adjustment; 
    by locnid date; 
run; 

data have2; 
    merge have(in=_h) adjustment(in=_a); 
    by locnid date; 
    retain __delflag __a1 __a2 __area; 
    if first.locnid then do; *clear the flags; 
    call missing(of __delflag __a1 __a2 __area); 
    end; 
    if not _a and not missing(__a1) then do; *if a previous change is pending; 
    a1=__a1; 
    a2=__a2; 
    area=__area; 
    end; 
    if _a and _h and type='change' then do; *if a change is implemented; 
    __a1=a1; 
    __a2=a2; 
    __area=area; 
    __delflag=0; *Not sure if this should be possible, but in case; 
    end; 
    else if _a and _h and type='close' then do; *if a delete is needed; 
    __delflag=1; 
    end; 

    if __delflag=1 then delete; 
    output; 
run; 

SAS가 시간을 거슬러 올라가서 각 레코드를 확인하지 않아도되기 때문에 이것은 1 초 안에 실행됩니다. 나는 이것이 당신이 원하는 것을 정확히 복제하는지 확신하지 못하지만, 그것과 거의 비슷한 것을해야합니다.

data have3; 
    merge have(in=_h) adjustment(in=_a); 
    by locnid date; 
    retain __delflag; 
    if first.locnid then do; 
    call missing(__delflag); 
    end; 
    if _a and _h and type = 'close' then do; 
    __delflag=1; 
    end; 
    if __delflag=1 and not (type in ('open','change')) then delete; 
    output; 
    if _a and _h and type='change' then __delflag=1; 
    if last.locnid then do; 
    call missing(of __:); 
    end; 
run; 

내가 전파 부분을 제거하면 삭제 그 기록 후 변화, 나중에 개방/변경 기록을 삭제하지 않도록 삭제에 몇 가지 매개 변수를 추가 :

SAS에서 A1의 정확한 복제본이 있습니다 . (실제 데이터에서는 가능하지 않을 수도 있습니다. 닫은 후에 열거 나 변경이 가능한 가짜 데이터를 사용하는 복제본입니다.)

관련 문제