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オプションを
指定すると処理速度が低下しました。コピーしないのになぜだろう?