简体   繁体   English

谷歌应用脚本超出执行时间限制

[英]Google app script exceeded execution time limit

I have a Google sheet with almost 160 sub sheets.我有一个包含近 160 个子工作表的 Google 工作表。 All the questions are in "All" sheet and B column is the actual spreadsheet name where they should be.所有问题都在“全部”表中,B 列是它们应该在的实际电子表格名称。 The following code is reading data from "All" spreadsheet and sending them perfectly to the last row of desired spreadsheet perfectly but it is taking very long time.以下代码正在从“所有”电子表格中读取数据,并将它们完美地发送到所需电子表格的最后一行,但这需要很长时间。 Probably because it has a lot of subsheets and is using getSheetByName again and again.可能是因为它有很多子表并且一次又一次地使用 getSheetByName。 Now I've stored all the sub sheets' name and ID in 'sheets' and 'sheetID' arrays at once.现在我已经将所有子工作表的名称和 ID 一次存储在“工作表”和“工作表 ID”arrays 中。 I'm thinking to compare between rangeValues[j][1] and sheetNames[k][0] .我正在考虑比较rangeValues[j][1]sheetNames[k][0] Below is the code and screenshot of the spreadsheet.以下是电子表格的代码和屏幕截图。

Is this a suitable way?这是合适的方式吗? Please help me to run the script faster!请帮助我更快地运行脚本!

 var ss = SpreadsheetApp.getActiveSpreadsheet(); var sheet = ss.getSheetByName("All"); var rangeData = sheet.getDataRange(); var lastRow = rangeData.getLastRow(); var searchRange = sheet.getRange(1,1, lastRow, 8); var curr_sheet; function send() { var rangeValues = searchRange.getValues(); var sheetNames = new Array(); var sheets = SpreadsheetApp.getActiveSpreadsheet().getSheets(); for (var i=0; i<sheets.length; i++) sheetNames.push( [ sheets[i].getName() ] ); //Logger.log (sheetNames.length); var sheetID = new Array(); var sheetIDs = SpreadsheetApp.getActiveSpreadsheet().getSheets(); for (var i=0; i<sheetIDs.length; i++) sheetID.push( [ sheetIDs[i].getSheetId() ] ); //Logger.log (sheetID.length); for ( j = 0; j < lastRow; j++) { for ( k = 0; k < sheetNames.length; k++) // { if (rangeValues[j][1] === sheetNames[k][0]) { var targetSheet = ss.getSheetByName(sheetNames[k][0]); // This line is working but taking very long to complete var targetSheet = ss.getSheetByID(sheetIDs[k][0]); // This line is not code just to show what I'm thinking to do. targetSheet.getRange(targetSheet.getLastRow()+1, 1, 1, 8).setValues([rangeValues[j]]); } } } }

在此处输入图像描述

I believe your goal as follows.我相信你的目标如下。

  • You want to reduce the process cost of your script.您想降低脚本的处理成本。

Modification points:修改点:

  • There is no method of getSheetByID in Class Spreadsheet. Class 电子表格中没有getSheetByID的方法。 By this, I think that in your case, the following script can be removed.这样,我认为在您的情况下,可以删除以下脚本。

     var sheetID = new Array(); var sheetIDs = SpreadsheetApp.getActiveSpreadsheet().getSheets(); for (var i=0; i<sheetIDs.length; i++) sheetID.push( [ sheetIDs[i].getSheetId() ] );
  • In your script, getSheetByName and getRange(###).setValues(###) are used in the loop.在您的脚本中,循环中使用了getSheetByNamegetRange(###).setValues(###) And also, even when the sheet is the same sheet, each row is put using setValues in the loop every row.而且,即使工作表是同一张工作表,每一行都会在每一行的循环中使用setValues放置。 In this case, the process cost will be high.在这种情况下,处理成本会很高。 I think that these situation might be the reason of your issue.我认为这些情况可能是您的问题的原因。

  • Fortunately, in your situation, all sheets are in the same Spreadsheet.幸运的是,在您的情况下,所有工作表都在同一个电子表格中。 So for reducing the process cost of your script, here, I would like to propose to put the values to each sheet using Sheets API.因此,为了降低脚本的处理成本,在这里,我想建议使用 Sheets API 将值放入每个工作表。 The flow of modified script is as follows.修改脚本的流程如下。

    1. Retrieve Spreadsheet and values.检索电子表格和值。
      • This script is from your script.该脚本来自您的脚本。
    2. Retrieve all sheets in the Spreadsheet.检索电子表格中的所有工作表。
    3. Check whether the sheet names from the column "B" are existing.检查“B”列中的工作表名称是否存在。
    4. Create the object for putting to each sheet using Sheets API.使用 Sheets API 创建 object 用于放置到每张纸上。
    5. Request the method of spreadsheets.values.batchUpdate of Sheets API using the created object.使用创建的 object 请求表格 API 的电子表格.values.batchUpdate 方法。

When above points are reflected to your script, it becomes as follows.当以上几点反映到您的脚本时,它变成如下。

Modified script:修改后的脚本:

Please copy and paste the following script.请复制并粘贴以下脚本。 And, please enable Sheets API at Advanced Google services .并且, 请在高级 Google 服务中启用表格 API And then, please run the script.然后,请运行脚本。

function send() {
  // 1. Retrieve Spreadsheet and values. This script is from your script.
  var ss = SpreadsheetApp.getActiveSpreadsheet();
  var sheet = ss.getSheetByName("All");
  var rangeData = sheet.getDataRange();
  var lastRow = rangeData.getLastRow();
  var searchRange = sheet.getRange(1,1, lastRow, 8);
  var curr_sheet;
  var rangeValues = searchRange.getValues();
  
  // 2. Retrieve all sheets in the Spreadsheet.
  var sheets = ss.getSheets().reduce((o, e) => Object.assign(o, {[e.getSheetName()]: e}), {});
  
  // 3. Check whether the sheet names from the column "B" are existing.
  // 4. Create the object for putting to each sheet using Sheets API.
  var data = rangeValues.reduce((o, e) => {
    if (sheets[e[1]]) {
      if (o[e[1]]) {
        o[e[1]].values.push(e);
      } else {
        o[e[1]] = {range: `'${e[1]}'!A${sheets[e[1]].getLastRow() + 1}`, values: [e]};
      }
    }
    return o;
  }, {});
  
  // 5. Request the method of spreadsheets.values.batchUpdate of Sheets API using the created object.
  Sheets.Spreadsheets.Values.batchUpdate({data: Object.values(data), valueInputOption: "USER_ENTERED"}, ss.getId());
}

Note:笔记:

  • In this case, when you run the script, one API call is used.在这种情况下,当您运行脚本时,将使用一个 API 调用。 Because the method of spreadsheets.values.batchUpdate is used.因为使用了电子表格.values.batchUpdate 的方法。
  • In my environment, when I tested above script and your script using a sample Spreadsheet, I could confirm the reduction of the process cost of about 70 % from your script.在我的环境中,当我使用示例电子表格测试上述脚本和您的脚本时,我可以确认您的脚本减少了大约 70% 的流程成本。

References:参考:

Try this:尝试这个:

Should be a lot faster应该快很多

function send() {
  var ss=SpreadsheetApp.getActive();
  var sh=ss.getSheetByName("All");
  var rg=sh.getRange(1,1,sh.getLastRow(),8);
  var v=rg.getValues();
  var names=[];
  var sheets=ss.getSheets();
  sheets.forEach(function(sh,i){names.push(sh.getName());});
  v.forEach(function(r){
    let idx=names.indexOf(r[1]);//column2
    if(idx!=-1) {
      sheets[idx].getRange(sheets[idx].getLastRow()+1,1,1,8).setValues([r]);
    }   
  });
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM