15# nkwilling
我再来补充一下。
keep=放在括号里面并不一定比放在外面效率高,要分情况来看。
其实keep=的data set option也要分两种情况:
1.KEEP= on SET statement
2.KEEP= on DATA statement
data step的运行机制用the little sas book的经典的话就是line by line,所以KEEP= on DATA statement这个情况其实和keep statement(即keep放在外面)的效率是相似的,是对于在pdv中的每条observation都要做keep计算,和buffers无关。一般data step中的效率问题基本上都集中在一个方面,就是buffers到pdv这个阶段,如果数据在buffers中做完过滤,那么就不需要在pdv中迭代逐条来做重复的过滤动作浪费时间,而set statement的data set option中过滤一般都是直接对buffers进行过滤。所以其效率要更高一些,不过也要看情况(楼主就有个很好的例子,以下会说到),当然由于直接走的是buffers,CPU和IO的消耗也会大一些。
还有关于where statement,它有些特殊,和where= data set option一样,都是对buffers进行过滤。if statement就不用说了,其过滤动作在pdv中迭代进行。
所以楼主的1楼的贴子为何表b还稍显快的原因就在这:
data a(keep=x1);——
虽然下面的set statement中已经有了对buffers的过滤,但是这里的keep无疑是对pdv的过滤,
即使buffers加载给pdv的数据已经没有了变量x1,但这个keep造成的计算仍然在执行,因此这里这条语句会产生额外的计算
set table(keep=x1 where=(x1>100));——
where和keep都是对buffers的过滤。
run;
data b;
set table;
where x1>100;——
where仍然是对buffers进行过滤
keep x1;——
keep则是对pdv进行过滤
run;
因此可以看到由于表a相比表b,都对pdv进行了keep过滤和对buffers进行了where过滤,但不同的是,表a还对buffers进行keep过滤,此计算量的增加造成了效率的损失。
继续解释9楼的结果:
22
23 data a2;
24 set table(keep=x where=(x='0000497604'));
25 run;
NOTE: “DATA 语句”所用时间(总处理时间):
实际时间 45.79 秒
CPU 时间 4.09 秒
NOTE: 从数据集 WORK.TABLE 读取了 2 个观测。
WHERE x='0000497604';
NOTE: 数据集 WORK.A2 有 2 个观测和 1 个变量。
26 data b2;
27 set table;
28 keep x;
29 where x='0000497604';
30 run;
NOTE: “DATA 语句”所用时间(总处理时间):
实际时间 44.18 秒
CPU 时间 3.95 秒
这里有点特殊,个人感觉这段代码由于结果只有2条observation,所以效率分析更加麻烦。以下仅供参考:前者
对buffers的计算是where和keep,后者只是where,后者还对pdv进行了keep计算。在对计算量进行分析之前,基于40+s的运行时间,因此做这样一个保守假设,假设原数据有1W条observation,而前者和后者的where效率,没问题,一致的,那么效率的差异就体现在双方keep的计算量上,虽然前者的keep是对buffers进行过滤,但buffers只是一个缓冲且有定长,依赖于memory,所以它并不足以大到可以吃掉整个dataset,关于buffers大小,proc contents可以看到,所以buffers的load是分块的,其频数个人认为等于contents中的number of pages,因此前者keep的计算量应该是等同于buffers的load频数,而后者,keep是对pdv中observation进行计算,这个例子中,对buffers进行过滤后,load在pdv中observation只有2条了,因此keep的计算量只有2次。基于这个计算量上的差异,后者的效率要高于前者。