【问题标题】:Google spreadsheet script very slow谷歌电子表格脚本非常慢
【发布时间】:2018-01-18 14:44:42
【问题描述】:

我有一个每天运行的脚本。它非常慢,我无法弄清楚是什么让它变慢了。有人有什么建议吗?我最初写了一个函数来做一张纸,然后我添加了一个函数来循环并在每张纸上调用它。

function addAllLog() {
  var ss        = SpreadsheetApp.getActiveSpreadsheet();
  var allSheets = ss.getSheets();
  // build array of all sheets
  for (var i in allSheets) { 
    if (i == 0) { continue;}  // skip first sheet

    var tmpName = allSheets[i].getName();
    if (tmpName == "Print Sheet")  break;  //stop at this tab

    var tmpName = ss.getSheetByName(allSheets[i].getName());
    ss.setActiveSheet(ss.getSheetByName(allSheets[i].getName()));

    addLog();
  }
}

function addLog () {
    var sheet = SpreadsheetApp.getActiveSheet();
    var numLastRow = sheet.getLastRow();
    var numThisRow = numLastRow+1;
    today = new Date();
    today.setDate(today.getDate()-1);
    today = Utilities.formatDate(today,"EDT","MM/DD/YYYY");

    if (sheet.getMaxRows() == numLastRow) sheet.insertRowAfter(numLastRow);

    var range = sheet.getRange(numLastRow,2,1,16); // last row, column b, 1 row of 16 columns
    var data = range.getValues();

    range.copyTo(sheet.getRange(numLastRow+1, 2,1,16)); //you will need to define the size of the copied data see getRange()

    sheet.getRange(numThisRow, 1).setValue(today);
    sheet.getRange(numThisRow, 4).setValue('Log');
    sheet.getRange(numThisRow, 5).setValue('');  //erase copied value if there was anything there
    sheet.getRange(numThisRow, 7).setValue('');  //erase copied value if there was anything there

    sheet.getRange(numThisRow, 6).setValue('=GoogleFinance(C' + numThisRow + ',"price")');
    sheet.getRange(numThisRow, 6).setValues(sheet.getRange(numThisRow,6).getValues());

}

任何关于加快速度的建议将不胜感激!

【问题讨论】:

    标签: performance google-apps-script google-sheets


    【解决方案1】:

    每次直接在电子表格上设置一个范围内的值时,至少需要 800 毫秒,因此解决此问题的最佳方法是使用这些值创建一个 Object[][] 并使用 sheet.getRange(range).setValues(Object[][]) 进行设置,确保Object[][] 具有与range 相同的宽高。

    在这篇 Best Practices | Apps Script 的帖子中,Google 解释了其中的区别。

    另外,一个有趣的解决方案是创建一个Spreadsheet abstraction in memory。我基于这种方法制作了自己的MemsheetApp,效果非常好。如果你想改进它,我会收到拉取请求。

    【讨论】:

      【解决方案2】:

      此版本不需要您激活每张工作表,因此可能需要更少的时间。

      function addAllLog() {
        var ss=SpreadsheetApp.getActive();
        var allSheets = ss.getSheets();
        for (var i=1;i<allSheets.length;i++){ 
          var shtname = allSheets[i].getName();
          if (shtname == "Print Sheet"){
            break;  //stop at this tab
          }else{
            addLog(shtname);
          }
        }
      }
      
      function addLog (shtname) {
        var sheet = SpreadsheetApp.getSheetByName(shtname);
        var numLastRow = sheet.getLastRow();
        var numThisRow = numLastRow+1;
        today = new Date();
        today.setDate(today.getDate()-1);
        today = Utilities.formatDate(today,"EDT","MM/DD/YYYY");
        if (sheet.getMaxRows() == numLastRow) sheet.insertRowAfter(numLastRow);
        var range = sheet.getRange(numLastRow,2,1,16); 
        range.copyTo(sheet.getRange(numLastRow+1, 2,1,16)); 
        sheet.getRange(numThisRow, 1).setValue(today);
        sheet.getRange(numThisRow, 4).setValue('Log');
        sheet.getRange(numThisRow, 5).setValue('');
        sheet.getRange(numThisRow, 7).setValue('');
        sheet.getRange(numThisRow, 6).setFormula('=GoogleFinance(C' + numThisRow + ',"price")');
      }
      

      【讨论】:

      • 我尝试使用数组,但是很多单元格中有公式。当我做var data = range.getValues(); 时,它只得到实际值,所以它没有公式。我取出了大部分setValues,这似乎并没有影响速度。我将数据内容移到了函数之外,因此它是一个全局变量并且没有效果(不是我想的那样)。我只是不明白为什么每张纸需要 30 秒来复制行并更改几个单元格。 b/c 需要很长时间,我无法将其设置为自动触发器。
      • 我做了一些小改动,可能会加快速度。您不想在文件顶部显示最近的值吗?
      • 我进行了这些更改,其中有一行没有做任何我需要删除的操作。我在顶部有最新的数据,但真的不喜欢它所以回去了。看起来最慢的线路实际上是range.copyTo 线路。必须有另一种方法来解决这个问题,复制公式和数据。
      • 如果你想复制公式和数据copyTo是最好的方法。
      猜你喜欢
      • 2023-04-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-04-01
      • 2012-06-15
      • 2018-03-05
      • 2014-09-03
      相关资源
      最近更新 更多