書いてはいけないGoogleAppScript

仕事でGoogleSpreadsheetのデータを操作してFusion Tablesに取り込むGoogleAppScriptを書いていたが、本番データ流してみたら処理時間が5分経ったところで処理が中断してしまった。

eye4brain.sakura.ne.jp

どうやら5分を超えると処理が中断する仕様で、それ以上長い処理をしたい場合はリンク先みたいなめんどくさいことをしないといけないらしい。正直この処理を組み込むのめんどくさいし、毎日やろうと思っている処理にこんな時間を掛けたくない。

www.slideshare.net

原則に立ち返ってファイルの実行トランスクリプトをみると「sheet.getRange().getValue()」ずらりと並んでいた。てっきりFusion Tablesへの取り込みに時間がかかっているのかと思っていたが、とんだ拍子抜けというか、for文の中でgetRange().getValue()を繰り返すとんだ悪手を実行していた。ざっと下記のような雰囲気だ。

for (i = 0; i>=1000 ;i++){
    sheet.getRange(i,1),getValue();
    //検査の処理を書いてる
}

GoogleAppScriptでは、シートへの通信を繰り返すとパフォーマンスが大幅に落ちるらしい。まぁ1行単位の入出力を繰り返すなんてことはGoogleAppsに限らず当然ダメな行為なんだけど・・・。

一応、そんな初歩的なアンチパターンは踏んでいないつもりだったのだけれども、点検したら書くのがめんどくさくて拾ってコピペしたちょっとしたモジュールが悪さをしていた。 参考までに言うと、列の最終行を取得するだけの関数で、標準のgetLastrowメソッドはシートに対しては全列の最終入力行、範囲に対しては空白行も含む範囲の最終行を返すからだ。なぜそんな仕様のメソッドが必要なのか一欠片も理解できない。Googleのエンジニアが間違って書いて、すでにその仕様にしかがって使われ始めてしまったものだから、あとから修正できなくなってしまったとしか思えない。 それを自分で書くのがめんどくさくて、適当に検索して拾ってきたのを使ったのがよくなかった。拾って使うにしても、せめて点検ぐらいするべきだった。その後、モジュールを下のような感じで修正した。

var values = sheet.getRange(1,1,1000).getValues();
for (i = 0; i>=999 ;i++){
    values[i][1]
    //あとはなんか検査の処理を書いてる
}

処理は20秒ぐらいで終わって、これであれば日時で想定している処理を全部やっても1分前後で終わりそうだ。Fusion Tablesの扱いについてはまた今度書く。

とりあえず拾ったコードをレビューせずに使うのはやめようと心に誓った。