12

400 個のオブジェクトのリストを反復処理するスクリプトがあるとします。各オブジェクトには、1 ~ 10 個のプロパティがあります。各プロパティは、適切なサイズの文字列またはやや大きな整数です。

これらのオブジェクトを ScriptDB に保存する場合とスプレッドシートに保存する場合のパフォーマンスに大きな違いはありますか (1 回の一括操作で行う必要はありません)。

4

2 に答える 2

30

エグゼクティブサマリー

はい、大きな違いがあります!巨大!そして、この実験が私が期待したようにはならなかったことを認めなければなりません。

この量のデータでは、スプレッドシートへの書き込みは常に、ScriptDB を使用するよりもはるかに高速でした。

これらの実験は、 Google Apps スクリプトのベスト プラクティスの一括操作に関する主張を裏付けています。単一のsetValues()呼び出しを使用してスプレッドシートにデータを保存すると、行単位よりも 75% 速く、セル単位よりも 2 桁速くなりました。

一方、Spreadsheet.flush()パフォーマンスへの影響があるため、使用する推奨事項は慎重に検討する必要があります。これらの実験では、4000 セルのスプレッドシートの 1 回の書き込みにかかる時間は 50 ミリ秒未満でした。呼び出しを追加すると、flush()それが 610 ミリ秒に増加しました。それでも 1 秒未満ですが、1 桁の税金はばかげているように見えます。サンプル スプレッドシートの 400 行のそれぞれを呼び出すflush()と、操作に約 12 秒かかりましたが、それがない場合は 164 ミリ秒しかかかりませんでした。Exceeded maximum execution timeエラーが発生している場合は、コードを最適化し、flush().

実験結果

すべてのタイミングは、関数の実行にかかる時間を測定する方法で説明されている手法に従って導出されました。時間はミリ秒単位で表されます。

以下は、5 つの異なるアプローチ (2 つは を使用ScriptDB)、3 つはスプレッドシートへの書き込み、すべて同じソース データを使用した 1 回のパスの結果です。(5 つの文字列と 5 つの数値属性を持つ 400 個のオブジェクト)

実験1

  • ScriptDB/Object テストの経過時間: 53529
  • ScriptDB/Batch テストの経過時間: 37700
  • スプレッドシート/オブジェクト テストの経過時間: 145
  • スプレッドシート/属性テストの経過時間: 4045
  • スプレッドシート/バルク テストの経過時間: 32

の効果Spreadsheet.flush()

実験2

この実験では、実験 1 との唯一の違いは、呼び出しSpreadsheet.flush()のたびにsetValue/s呼び出しを行ったことです。そうすることのコストは劇的 (約 700%) ですが、スプレッドシートへの書き込みは依然として高速であるため、速度の理由から ScriptDB よりもスプレッドシートを使用するという推奨事項は変わりません。

  • ScriptDB/Object テストの経過時間: 55282
  • ScriptDB/Batch テストの経過時間: 37370
  • スプレッドシート/オブジェクト テストの経過時間: 11888
  • スプレッドシート/属性テストの経過時間: 117388
  • スプレッドシート/バルク テストの経過時間: 610

注: この実験は、Exceeded maximum execution timeで頻繁に強制終了されました。

買い手責任負担

あなたはインターウェブでこれを読んでいるので、それは本当でなければなりません! しかし、一粒の塩でそれを取ります。

  • これらは非常に小さなサンプル サイズからの結果であり、完全に再現できない場合があります。
  • これらの結果は、常に変化するものを測定しています。2013 年 2 月 28 日に観測されたものですが、これを読むと、測定されたシステムが完全に異なる可能性があります。
  • これらの操作の効率は、これらの実験では制御されていない多くの要因の影響を受けます。たとえば、命令と中間結果のキャッシュ、およびサーバー負荷。
  • ひょっとしたら、Google の誰かがこれを読んで、ScriptDB の効率を改善するかもしれません!

コード

これらの実験を実行したい (またはさらに改善したい) 場合は、空のスプレッドシートを作成し、これをその中の新しいスクリプトにコピーします。これはgist としても利用できます。

/**
 * Run experiments to measure speed of various approaches to saving data in
 * Google App Script (GAS).
 */
function testSpeed() {
  var numObj = 400;
  var numAttr = 10;
  var doFlush = false;  // Set true to activate calls to SpreadsheetApp.flush()

  var arr = buildArray(numObj,numAttr);
  var start, stop;  // time catchers
  var db = ScriptDb.getMyDb();
  var sheet;

  // Save into ScriptDB, Object at a time
  deleteAll(); // Clear ScriptDB
  start = new Date().getTime();
    for (var i=1; i<=numObj; i++) {
      db.save({type: "myObj", data:arr[i]});
    }
  stop = new Date().getTime();
  Logger.log("Elapsed time for ScriptDB/Object test: " + (stop - start));

  // Save into ScriptDB, Batch
  var items = [];
  // Restructure data - this is done outside the timed loop, assuming that
  // the data would not be in an array if we were using this approach.
  for (var obj=1; obj<=numObj; obj++) {
    var thisObj = new Object();
    for (var attr=0; attr < numAttr; attr++) {
      thisObj[arr[0][attr]] = arr[obj][attr];
    }
    items.push(thisObj);
  }
  deleteAll(); // Clear ScriptDB
  start = new Date().getTime();
    db.saveBatch(items, false);
  stop = new Date().getTime();
  Logger.log("Elapsed time for ScriptDB/Batch test: " + (stop - start));

  // Save into Spreadsheet, Object at a time
  sheet = SpreadsheetApp.getActive().getActiveSheet().clear();
  start = new Date().getTime();
    for (var row=0; row<=numObj; row++) {
      var values = [];
      values.push(arr[row]);
      sheet.getRange(row+1, 1, 1, numAttr).setValues(values);
      if (doFlush) SpreadsheetApp.flush();
    }
  stop = new Date().getTime();
  Logger.log("Elapsed time for Spreadsheet/Object test: " + (stop - start));

  // Save into Spreadsheet, Attribute at a time
  sheet = SpreadsheetApp.getActive().getActiveSheet().clear();
  start = new Date().getTime();
    for (var row=0; row<=numObj; row++) {
      for (var cell=0; cell<numAttr; cell++) {
        sheet.getRange(row+1, cell+1, 1, 1).setValue(arr[row][cell]);
        if (doFlush) SpreadsheetApp.flush();
      }
    }
  stop = new Date().getTime();
  Logger.log("Elapsed time for Spreadsheet/Attribute test: " + (stop - start));

  // Save into Spreadsheet, Bulk
  sheet = SpreadsheetApp.getActive().getActiveSheet().clear();
  start = new Date().getTime();
    sheet.getRange(1, 1, numObj+1, numAttr).setValues(arr);
    if (doFlush) SpreadsheetApp.flush();
  stop = new Date().getTime();
  Logger.log("Elapsed time for Spreadsheet/Bulk test: " + (stop - start));
}

/**
 * Create a two-dimensional array populated with 'numObj' rows of 'numAttr' cells.
 */
function buildArray(numObj,numAttr) {
  numObj = numObj | 400;
  numAttr = numAttr | 10;
  var array = [];
  for (var obj = 0; obj <= numObj; obj++) {
    array[obj] = [];
    for (var attr = 0; attr < numAttr; attr++) {
      var value;
      if (obj == 0) {
        // Define attribute names / column headers
        value = "Attr"+attr;
      }
      else {
        value = ((attr % 2) == 0) ? "This is a reasonable sized string for testing purposes, not too long, not too short." : Number.MAX_VALUE;
      }
      array[obj].push(value);
    }
  }
  return array
}

function deleteAll() {
  var db = ScriptDb.getMyDb();
  while (true) {
    var result = db.query({}); // get everything, up to limit
    if (result.getSize() == 0) {
      break;
    }
    while (result.hasNext()) {
      var item = result.next()
      db.remove(item);
    }
  }
}
于 2013-03-01T03:25:17.143 に答える
4

ScriptDB は廃止されました。使用禁止。

于 2014-05-23T18:57:00.920 に答える