我构建了自己的应用脚本代码,以从转储文件中更新日期。 我大多数时候都面临“超出最大执行时间”的问题。但是代码工作正常。它从工作表(29 k行)导入和更新数据(16.5 K行)的状态 您可以支持使代码更快/工作正常吗?
function update_main_master() {
var xngSs = SpreadsheetApp.openById('XXXX');
var xngSh = xngSs.getSheetByName('XNG Clean Data');
var MasterSs = SpreadsheetApp.openById('YYY');
var MasterSh = MasterSs.getSheetByName('Master Sheet');
var MasterData = MasterSh.getDataRange().getValues();
var xngData = xngSh.getDataRange().getValues();
// clearFilter()
if (MasterSh.getFilter() != null) {
MasterSh.getFilter().remove();
}
xngData.splice(0, 1);
MasterData.splice(0, 1);
var OrderNumberMasterSh = [];
var PathNameMasterSh = [];
for (var i = 0; i < MasterData.length; i++) {
OrderNumberMasterSh.push(MasterData[i][1]);
PathNameMasterSh.push(MasterData[i][2]);
}
var i = 0;
for (var x = 0; x < xngData.length && xngData[x][3] != undefined; x++) {
var OrderNumber = xngData[x][3];
var OrderDate = xngData[x][2];
var PathName = xngData[x][4];
var CustomerName = xngData[x][5];
var MW_contractor = xngData[x][8];
var OrderStatus = xngData[x][9];
var OrderStage = xngData[x][10];
var ProjectID = xngData[x][14];
var OrderType = xngData[x][41];
var StageDate = xngData[x][11];
var InService = xngData[x][28];
var RejectedReason = xngData[x][31];
var District = xngData[x][15];
var LinkID = xngData[x][24];
var NewOrder = 'New Order';
if (MW_contractor == 'A' || MW_contractor == 'B' || MW_contractor == 'C') {
if (
OrderType == 'New' ||
OrderType == 'Repeater' ||
OrderType == 'Visibility'
) {
// if(OrderType == "New" || OrderType == 'Repeater')
var index = OrderNumberMasterSh.indexOf(OrderNumber);
if (index == -1) {
MasterData.push([
OrderDate,
OrderNumber,
PathName,
CustomerName,
ProjectID,
MW_contractor,
OrderStatus,
OrderStatus,
OrderStage,
OrderType,
StageDate,
InService,
'',
District,
'',
NewOrder,
'',
'',
'',
'',
'',
'',
'',
'',
'',
'',
'',
'',
'',
'',
'',
'',
'',
'',
'',
'',
'',
'',
'',
'',
'',
'',
'',
'',
'',
'',
'',
'',
RejectedReason,
'',
'',
'',
'',
'',
'',
'',
'',
'',
'',
]);
} else {
MasterData[index][4] = ProjectID;
MasterData[index][5] = MW_contractor;
MasterData[index][7] = OrderStatus;
MasterData[index][8] = OrderStage;
MasterData[index][10] = StageDate;
MasterData[index][11] = InService;
if (MasterData[index][51] == '') {
MasterData[index][51] = LinkID;
}
if (
OrderStatus == 'IN-PROCESS' ||
OrderStatus == 'CANCELLED' ||
OrderStatus == 'REJECTED'
) {
MasterData[index][6] = OrderStatus;
}
if (OrderStatus == 'COMPLETED') {
MasterData[index][6] = 'LIVE';
}
if (OrderStatus == 'REJECTED' && MasterData[index][48] == '') {
MasterData[index][48] = RejectedReason;
}
}
}
}
}
var ContorlSS = SpreadsheetApp.openById('ZZZZ');
var ContorlSh = ContorlSS.getSheetByName('Setup');
ContorlSh.getRange('F6').setValue('Updated');
ContorlSh.getRange('G6').setValue(new Date());
MasterSh.getRange(2, 1, MasterData.length, MasterData[0].length).setValues(
MasterData
);
SpreadsheetApp.flush();
}
我构建了自己的应用脚本代码,以从转储文件中更新日期。我大多数时候都遇到“超出最大执行时间”的问题。但是代码工作正常。它可以导入并更新工作表具有(29k行)的数据(16.5万行)的状态,您可以支持使代码更快/工作正常吗?
答案 0 :(得分:1)
您已达到执行时间限制,对于大多数帐户来说,这是6分钟。为避免这种情况,您可以通过设置基于时间的触发器将循环分成不同的执行,该触发器将在上一个执行完成后触发每个后续执行。您将必须执行以下操作:
在每次迭代后检查执行时间。如果该时间接近时间限制,则停止执行。您可以为此使用Date object。
在函数结尾创建以下基于时间的触发器:after(durationMilliseconds)。因此,您可以在指定的毫秒数后运行指定的任何功能。每次执行后,都会创建一个触发器来触发下一个触发器。
由于要拆分循环,因此必须将循环计数器(x
)存储在某个位置(可以在每次执行结束时使用PropertiesService或将其写入电子表格),并在下一个开始处进行检索,这样,在每次连续执行时,脚本都知道在哪里恢复循环。例如,如果您不知道如何存储和检索脚本属性,请参见this answer。
现在,您正在将所需的所有数据存储在2D数组MasterData
中,并在代码末尾使用setValues
将此数据写入电子表格。由于此操作仅在循环完成后才发生,因此如果将循环分成多个执行,则这是不合适的。我建议您修改代码,以便在循环内进行编写过程,并从代码末尾删除setValues
。您将必须如以下示例中那样更改代码。
例如,尝试更改此内容:
MasterData[index][48] = RejectedReason;
与此:
MasterSh.getRange(index + 1, 49).setValue(RejectedReason);
这:
MasterData.push([OrderDate, OrderNumber, ...]);
与此:
MasterSh.appendRow([OrderDate, OrderNumber, ...]);
function update_main_master() {
var begin = new Date(); // Time when execution begins
// Your code before loop
var x_old = // Retrieve x stored in previous execution (from PropertiesService? Spreadsheet?) (should be 0 if first execution)
var timeLimit = 1000 * 60 * 5; // 5 minutes (in milliseconds)
while (new Date() - begin < timeLimit) { // Check if 5 minutes passed since execution start
for (var x = 0; x < xngData.length && xngData[x][3] != undefined; x++) {
// Your code inside loop
}
}
// Store current x index (using PropertiesService? Or write to the spreadsheet itself?
var ContorlSS = SpreadsheetApp.openById('ZZZZ');
var ContorlSh = ContorlSS.getSheetByName('Setup');
ContorlSh.getRange('F6').setValue('Updated');
ContorlSh.getRange('G6').setValue(new Date());
if (x < xngData.length) { // Create trigger if x hasn't reach the total number of iteration
ScriptApp.newTrigger("update_main_master")
.timeBased()
.after(1000 * 60) // This fires the function 1 minute after the current execution ends. Change this time according to your preferences
.create();
}
}