테이블이 모두 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의 정확한 복제본이 있습니다 . (실제 데이터에서는 가능하지 않을 수도 있습니다. 닫은 후에 열거 나 변경이 가능한 가짜 데이터를 사용하는 복제본입니다.)
http://ftp.sas.com /techsup/download/observations/obswww19/obswww19.pdf에서 필요한 항목을 찾을 수 있습니다. – mjsqu