Что быстрее: ScriptDb или SpreadsheetApp?

Допустим, у меня есть скрипт, который перебирает список из 400 объектов. Каждый объект имеет от 1 до 10 свойств. Каждое свойство представляет собой строку разумного размера или несколько большое целое число.

Есть ли существенная разница в производительности при сохранении этих объектов в ScriptDB по сравнению с сохранением их в Spreadsheet(без выполнения одной массовой операции).

2 ответа

Решение

ScriptDB устарел. Не использовать.

Управляющее резюме

Да, есть существенная разница! Огромный! И я должен признать, что этот эксперимент оказался не таким, как я ожидал.

При таком объеме данных запись в электронную таблицу всегда выполнялась намного быстрее, чем при использовании ScriptDB.

Эти эксперименты подтверждают утверждения о массовых операциях в рекомендациях по использованию скриптов Google Apps. Сохранение данных в электронной таблице с использованием одного setValues() Вызов был на 75% быстрее, чем построчно, и на два порядка быстрее, чем сотовая связь.

С другой стороны, рекомендации по использованию Spreadsheet.flush() следует учитывать внимательно, из-за воздействия на производительность. В этих экспериментах одна запись таблицы из 4000 ячеек заняла менее 50 мс, и добавление вызова flush() увеличено до 610 мсек - все равно меньше секунды, но налог на порядок кажется нелепым. призвание flush() для каждой из 400 строк в электронной таблице образцов операция заняла почти 12 секунд, а без нее всего 164 мс. Если вы столкнулись с ошибками превышения максимального времени выполнения, вы можете воспользоваться как оптимизацией кода, так и удалением вызовов flush(),

Результаты эксперимента

Все сроки были получены в соответствии с методикой, описанной в разделе Как измерить время, затраченное на выполнение функции. Время выражается в миллисекундах.

Вот результаты одного прохода пяти разных подходов, два с использованием ScriptDB три записи в электронные таблицы с одинаковыми исходными данными. (400 объектов с 5 строковыми и 5 числовыми атрибутами)

Эксперимент 1

  • Истекшее время для проверки ScriptDB/Object: 53529
  • Истекшее время для ScriptDB / пакетного теста: 37700
  • Истекшее время для проверки таблицы / объекта: 145
  • Истекшее время для проверки таблицы / атрибута: 4045
  • Истекшее время для таблицы / массового теста: 32

Эффект Spreadsheet.flush()

Эксперимент 2

В этом эксперименте единственным отличием от эксперимента 1 было то, что мы назвали Spreadsheet.flush() после каждого setValue/s вызов. Стоимость этого является значительной (около 700%), но не меняет рекомендацию использовать электронную таблицу поверх ScriptDB по соображениям скорости, поскольку запись в электронные таблицы все еще происходит быстрее.

  • Истекшее время для проверки ScriptDB / объекта: 55282
  • Истекшее время для ScriptDB / пакетного теста: 37370
  • Истекшее время для проверки таблицы / объекта: 11888
  • Истекшее время для проверки таблицы / атрибута: 117388
  • Истекшее время для таблицы / массового теста: 610

Примечание. Этот эксперимент часто завершался с превышением максимального времени выполнения.

Пусть покупатель будет бдителен

Вы читаете это на паутинах, так что это должно быть правдой! Но возьмите это с зерном соли.

  • Это результаты очень малых размеров выборки, которые могут быть не полностью воспроизводимыми.
  • Эти результаты измеряют то, что постоянно меняется - хотя они наблюдались 28 февраля 2013 года, система, которую они измерили, может быть совершенно другой, когда вы прочитаете это.
  • На эффективность этих операций влияют многие факторы, которые не контролируются в этих экспериментах; Например, кеширование инструкций и промежуточных результатов, а также загрузка сервера.
  • Может быть, просто может быть, кто-то из Google прочтет это и улучшит эффективность ScriptDB!

Код

Если вы хотите выполнить (или еще лучше улучшить) эти эксперименты, создайте пустую электронную таблицу и скопируйте ее в новый скрипт внутри нее. Это также доступно как суть.

/**
 * 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);
    }
  }
}
Другие вопросы по тегам