优化SAS Proc SQL查询

时间:2015-12-14 11:33:15

标签: sql join optimization sas proc

我正在尝试加入2个大表,以便根据第二个表中的字段对第一个记录进行分组。左表有大约50万个事件记录,右表有大约35万个月间隔记录。每月的间隔是在subjID级别,因此我不能通过仅保留开始和结束日期来减小右表的大小。目前,执行加入大约需要40-60分钟。

我尝试在subjID,eventDate,startDate和endDate上创建简单索引,但它似乎没有提高性能(创建索引在大约5分钟内完成,加入在38分钟内完成)。

我可以使用其他任何方法来改进处理吗?

在subjID级别的左表事件:

data eventsTable;
input @1 subjID 8.
    @10 eventDate date9.;
format eventDate mmddyy10.;
datalines;
101      01AUG2011
101      28AUG2011
101      30AUG2011
101      01SEP2011
101      12SEP2011
101      28SEP2011
102      01JAN2015
102      15JAN2015
102      01FEB2015
102      16FEB2015
;
run;

在subjID级别的每月间隔的右表。如果事件发生在开始日期和结束日期之间,我试图将endDate引入事件:

data monthlyTable;
input @1 subjID 8.
    @10 startDate date9. 
    @22 endDate date9.;
format startDate endDate mmddyy10.;
datalines;
101      28JUL2011   30AUG2011
101      30AUG2011   28SEP2011
101      28SEP2011   28OCT2011
102      01DEC2014   02JAN2015
102      02JAN2015   02FEB2015
102      02FEB2015   02MAR2015
;
run;

输出:

proc sql;
create table wantTable as 
    select a.*,
        endDate as monthlyDate
    from eventsTable a left join monthlyTable b on 
        a.subjID = b.subjID
    where a.eventDate > b.startDate and a.eventDate <= b.endDate
        order by subjID, eventDate;
quit;

3 个答案:

答案 0 :(得分:1)

如果你有足够的内存而你只需要来自enddate的{​​{1}},你可能会发现格式合并是一种更有效的方法。但是,如果两个数据集都很大,那么您可以希望只进行如此多的优化,因为您始终必须至少完全读取每个数据集。

monthlyTable

请注意data t_format(keep = fmtname--hlo) /view = t_format; set monthlytable(keep = subjID startdate enddate) end = eof; retain fmtname 'myinfmt' type 'i'; length start end $18; /*Increase for IDs longer than 8 digits*/ start = cats(put(subjID,z8.),put(startdate + 1,yymmdd10.)); end = cats(put(subjID,z8.),put(enddate,yymmdd10.)); label = enddate; output; if eof then do; hlo = 'O'; label = .N; output; end; run; proc format cntlin = t_format; run; data want; set eventstable; enddate = input(cats(put(subjID,z8.),put(eventdate,yymmdd10.)),myinfmt18.); format enddate yymmdd10.; run; yymmdd10.格式的使用 - 这些格式确保密钥长度始终相同,避免歧义,并且在创建时按升序正确指定查找值的范围数字信息z8.。我想,严格来说,这是一个 informat 合并而不是格式合并,但它是同样的想法。

如果你想通过这种方法返回多个查找变量,你需要在定义格式时将它们连接在一起,然后在应用它之后将它们拆分。

我估计这种方法需要大约1.5GB的内存用于您指定的数据集 - 即(每个日期范围18个字节x 2 +格式化值的8个字节)x 35m行。根据ID的长度,这可能会略有不同。

如果你需要多个查找值,那么你可以使用哈希合并做类似的事情,但我怀疑在这种情况下格式合并更有效。

一种可能的哈希合并方法如下所示:

myinfmt

答案 1 :(得分:0)

查询的最佳索引是monthlyTable(subjId, startDate, endDate)上的综合索引。不过,我不确定它在SAS性能方面是否会有很大改进。

答案 2 :(得分:0)

我对预先排序数据集比运行索引要好。但是,预排序可能需要很长时间,具体取决于数据集的大小以及对它们进行排序的内容。它可能需要比原始SQL查询更长的时间,因此测试变得很重要。

尝试运行

PROC SORT DATA=eventsTable ;
  BY subjID eventDate ;
RUN ;

PROC SORT DATA=monthlyTable ;
  BY subjID startDate endDate ;
RUN ;
在您的PROC SQL之前

。我唯一的解释是SAS识别SORT BY标头信息,并且不需要扫描整个表来查找连接,因为给定的subjID可能只在几个连续的页面上。连续几页也会降低I / O.