我輩はブロガーではない。ネタもまだない

SASとかDelphiあたりの人様の役に立たないネタを提供します

fetchとfetchobsの処理速度

かなり久しぶりの投稿です。

年始に余裕ぶっこいてたら、ちょっと危ないことになってしまいました。
プロジェクトは佳境です。

さて、今日はためにならないSCL、fetchとfetchobsのお話。


両者の違いを簡単に言うと、fetchは現在のobsの情報を取得、
fetchobsは指定したobsの情報を取得する、という違いがあります。

今管理しているソースに同じループをfetchとfetchobsで処理しているところが
あり、実際のところどっちが速いんだ?と気になって調べました。




/* fetch */
rc=rewind(dsid);
do while(fetch(dsid)=0);

/* fetchobs */
nobs=attrn(dsid,'nobs');
do i=1 to nobs;


まず、1万OBSのデータセットをループさせます
(10万obsだと途端にfetchobsが遅くなったので1万に減らしました。
あ、先に結果を書いてしまった…)

  dsid=open('work.test','I');
  if dsid>0 then do;
    nobs=attrn(dsid,'nobs');
    time=datetime();
      do while(fetch(dsid)=0);
        a=getvarn(dsid,1);
      end;
    time2=datetime()-time;
    put time2;

    time=datetime();
    do j=1 to nobs;
      rc=fetchobs(dsid,j);
      if rc=0 then a=getvarn(dsid,1);
    end;
    time2=datetime()-time;
    put time2;
    rc=close(dsid);
  end;

こんな感じのコードで、結果は以下の通りです。

fetch: 0.0019998550415
fetchobs:0.00399994850158

fetchはfetchobsの半分で処理が完了しています。


続いて、削除したobsがある、また、whereでobsを絞り込んでいるケースです。

dataステップで半分のobsをdelete(i>5000)し、更にfetch前にでさらに半分のobsを抽出(where(i<2500))します。
(実際にはobsの1/2と1/4で処理しています)

結果としては以下のようになりました。
nobsとnlobsが処理に時間がかかっているのは、nobsは削除したobsまでアクセスしているため、
nlobsはそれに加え、obs数を取得する時間もかかっているのではないかと思われます。(どちらも同じ値です)

fetch: 0.00300002098083
fetchobs(nobs): 0.27999997138977
fetchobs(nlobs): 0.55800008773803
fetchobs(nlobsf):0.00200009346008


nlobsfを使ったfetchobsが健闘しました。fetchobsは相対obsでダイレクトにアクセスするのに対し、
fetchは削除されていないobsを見に行くのに若干のオーバーヘッドがあるんでしょうか。





さらに対象obsを1万から10万に増やしてみました。

fetch: 0.01799988746643
fetchobs: 0.0329999923706

こちらの処理時間はおよそ9倍になっています。
大体fetchが半分くらいというのは同じ結果ですね。


続いて、削除&whereしたobsを対象とした結果です。

fetch: 0.018000125885
fetchobs(nlobsf):0.02600002288818

1万obsの結果と比べて逆転しました。
オブザベーション数を取得するのに時間がかかっているような感じなのか、と思いましたが、
attrn(dsid,'nlobsf') 行を計測時間から除外してもそんなに変わりませんでした。


結論としては、全てのobsを読み込むときにはfetchを使うのが確実かと思います。
fetchobsは指定したobsにアクセスしたいときにだけ使用するといった感じで使い分けを。


なお、データセット変数値をSCL変数に自動的にコピーしないようNOSETオプションを
指定すると処理速度が低下しました。コピーしないのになぜだろう?