performance - name - google script spreadsheet
¿Qué es más rápido: ScriptDb o SpreadsheetApp? (2)
Digamos que tengo una secuencia de comandos que itera sobre una lista de 400 objetos. Cada objeto tiene entre 1 y 10 propiedades. Cada propiedad es una cadena de tamaño razonable o un entero algo grande.
¿Hay una diferencia significativa en el rendimiento de guardar estos objetos en ScriptDB vs guardarlos en Spreadsheet (sin hacerlo en una operación masiva).
ScriptDB ha quedado obsoleto. No utilice.
Resumen ejecutivo
Sí, ¡hay una diferencia significativa! ¡Enorme! Y tengo que admitir que este experimento no resultó de la manera que esperaba.
Con esta cantidad de datos, escribir en una hoja de cálculo siempre fue mucho más rápido que usar ScriptDB.
Estos experimentos respaldan las afirmaciones sobre operaciones masivas en las mejores prácticas de Google Apps Script . Guardar datos en una hoja de cálculo usando una sola llamada setValues()
fue 75% más rápido que línea por línea, y dos órdenes de magnitud más rápido que celda por celda.
Por otro lado, las recomendaciones para usar Spreadsheet.flush()
deben considerarse cuidadosamente, debido al impacto en el rendimiento. En estos experimentos, una sola escritura de una hoja de cálculo de 4000 celdas tomó menos de 50ms, y agregar una llamada a flush()
aumentó eso a 610ms, aún menos de un segundo, pero un impuesto de orden de magnitud parece ridículo. Llamar a flush()
para cada una de las 400 filas en la hoja de cálculo de muestra hizo que la operación durara casi 12 segundos, cuando solo faltaban 164 ms sin ella. Si ha estado superando los errores de tiempo de ejecución excedidos , puede beneficiarse tanto de la optimización de su código como de la eliminación de llamadas a flush()
.
Resultados experimentales
Todos los tiempos se obtuvieron siguiendo la técnica descrita en Cómo medir el tiempo que tarda una función en ejecutarse . Los tiempos se expresan en milisegundos.
Estos son los resultados de una sola pasada de cinco enfoques diferentes, dos usando ScriptDB
, tres escribiendo en Hojas de cálculo, todos con la misma fuente de datos. (400 objetos con 5 atributos de cadena y 5 números)
Experimento 1
- Tiempo transcurrido para la prueba ScriptDB / Object: 53529
- Tiempo transcurrido para la prueba ScriptDB / Batch: 37700
- Tiempo transcurrido para la prueba Spreadsheet / Object: 145
- Tiempo transcurrido para la prueba de Hoja de cálculo / Atributo: 4045
- Tiempo transcurrido para la prueba Spreadsheet / Bulk: 32
Efecto de Spreadsheet.flush()
Experimento 2
En este experimento, la única diferencia con el Experimento 1 fue que llamamos a Spreadsheet.flush()
después de cada llamada a setValue/s
. El costo de hacerlo es dramático, (alrededor del 700%) pero no cambia la recomendación de usar una hoja de cálculo sobre ScriptDB por razones de velocidad, porque escribir en hojas de cálculo es aún más rápido.
- Tiempo transcurrido para la prueba ScriptDB / Object: 55282
- Tiempo transcurrido para la prueba ScriptDB / Batch: 37370
- Tiempo transcurrido para la prueba Spreadsheet / Object: 11888
- Tiempo transcurrido para la prueba de Hoja de cálculo / Atributo: 117388
- Tiempo transcurrido para la prueba Spreadsheet / Bulk: 610
Nota: Este experimento a menudo se eliminó con el tiempo de ejecución máximo excedido .
Caveat Emptor
Estás leyendo esto en los interwebs, ¡así que debe ser cierto! Pero tómalo con un grano de sal.
- Estos son resultados de tamaños de muestra muy pequeños, y pueden no ser completamente reproducibles.
- Estos resultados miden algo que cambia constantemente: mientras se observaron el 28 de febrero de 2013, el sistema que midieron podría ser completamente diferente al leer esto.
- La eficiencia de estas operaciones se ve afectada por muchos factores que no están controlados en estos experimentos; almacenamiento en caché de instrucciones y resultados intermedios y carga del servidor, por ejemplo.
- Tal vez, solo tal vez, alguien en Google leerá esto y mejorará la eficiencia de ScriptDB.
El código
Si desea realizar (o mejor aún, mejorar) estos experimentos, cree una hoja de cálculo en blanco y cópiela en una nueva secuencia de comandos dentro de ella. Esto también está disponible como una esencia .
/**
* 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);
}
}
}