Co jest szybsze: ScriptDb lub SpreadsheetApp?

Załóżmy, że mam skrypt a, który iteruje ponad listą 400 obiektów. Każdy obiekt ma od 1 do 10 właściwości. Każda właściwość jest ciągiem o rozsądnym rozmiarze lub nieco dużą liczbą całkowitą.

Czy istnieje znacząca różnica w wydajności zapisywania tych obiektów do ScriptDB zamiast zapisywania ich do arkusza kalkulacyjnego (bez wykonywania jednej operacji zbiorczej).

Author: Mogsdad, 2013-03-01

2 answers

ScriptDB został wycofany. Nie używać.

 3
Author: ScampMichael,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-05-23 18:57:00

Streszczenie

Tak, jest znacząca różnica! ogromny! i muszę przyznać, że ten eksperyment nie wyszedł tak, jak oczekiwałem.

Przy takiej ilości danych zapis do arkusza kalkulacyjnego był zawsze znacznie szybszy niż przy użyciu ScriptDB.

Te eksperymenty wspierają twierdzenia dotyczące operacji masowych w najlepszych praktykach skryptu Google Apps . Zapisywanie danych w arkuszu kalkulacyjnym za pomocą pojedynczego wywołania setValues() było o 75% szybsze niż linia po linii i dwa rzędy wielkości szybciej niż komórka po komórce.

Z drugiej strony, zalecenia dotyczące stosowania Spreadsheet.flush() należy dokładnie rozważyć ze względu na wpływ na wydajność. W tych eksperymentach pojedynczy zapis arkusza kalkulacyjnego 4000-komórkowego zajął mniej niż 50MS, a dodanie wywołania do flush() zwiększyło to do 610ms - nadal mniej niż sekundę, ale podatek rzędu wielkości wydaje się niedorzeczny. Wywołanie flush() dla każdego z 400 wierszy w przykładowym arkuszu kalkulacyjnym sprawiło, że operacja zajęła prawie 12 sekund, kiedy to zajęło tylko 164 ms bez niego. Jeśli wystąpi błąd przekroczony maksymalny czas wykonania , możesz skorzystać zarówno na optymalizacji kodu, jak i usunięciu wywołań do flush().

Wyniki Eksperymentalne

Wszystkie timingi zostały wyprowadzone zgodnie z techniką opisaną w Jak zmierzyć czas potrzebny funkcji do wykonania . Czasy są wyrażone w milisekundach.

Oto wyniki z jednego przejścia pięciu różnych podejść, dwa używając ScriptDB, trzy pisząc do arkuszy kalkulacyjnych, wszystkie z tymi samymi danymi źródłowymi. (400 obiektów z 5 atrybutami String & 5 Number)

Eksperyment 1

  • upłynął czas na test ScriptDB / Object: 53529
  • upłynął czas dla ScriptDB / Test wsadowy: 37700
  • upłynął czas testu arkusza kalkulacyjnego/ obiektu: 145
  • upłynął czas dla arkusza kalkulacyjnego / testu atrybutów: 4045
  • upłynął czas dla arkusza kalkulacyjnego / testu zbiorczego: 32

Efekt Spreadsheet.flush()

Eksperyment 2

W tym eksperymencie jedyną różnicą od eksperymentu 1 było to, że wywoływaliśmy Spreadsheet.flush() po każdym wywołaniu setValue/s. Koszt tego jest dramatyczny (około 700%), ale nie zmienia zalecenia, aby używać arkusza kalkulacyjnego nad ScriptDB ze względu na szybkość, ponieważ pisanie do arkuszy kalkulacyjnych jest nadal szybsze.

  • upłynął czas na test ScriptDB / Object: 55282
  • upłynął czas dla ScriptDB / Test wsadowy: 37370
  • upłynął czas na Test arkusza kalkulacyjnego/obiektu: 11888
  • upłynął czas dla arkusza kalkulacyjnego / testu atrybutów: 117388
  • upłynął czas dla arkusza kalkulacyjnego / testu zbiorczego: 610

Uwaga: eksperyment ten był często zabijany z przekroczeniem maksymalnego czasu wykonania.

Caveat Emptor

Czytasz to na interwebach, więc to musi być prawda! Ale weź to z przymrużeniem oka.

  • są to wyniki z bardzo małych rozmiarów próbek i mogą nie być całkowicie powtarzalne.
  • te wyniki mierzą coś, co ciągle się zmienia - podczas gdy zaobserwowano je 28 lutego 2013, System, który mierzyli, może być zupełnie inny, gdy to przeczytasz.
  • Na wydajność tych operacji wpływa wiele czynników, które nie są kontrolowane w tych eksperymentach; na przykład buforowanie instrukcji i wyników pośrednich oraz obciążenie serwera.
  • może, tylko może, ktoś z Google to przeczyta i poprawi efektywność ScriptDB!

Kod

Jeśli chcesz wykonać (lub jeszcze lepiej, poprawić) te eksperymenty, Utwórz pusty arkusz kalkulacyjny i skopiuj go do nowego skryptu w nim. jest to również dostępne jako 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);
    }
  }
}
 30
Author: Mogsdad,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 10:28:15