[英]Improve performance in Google App Script Search functions
I have written a script using Google App Script (in javascript) and I am looking for a way to be best optimize function that return objects, based on one or more search fields.我已经使用 Google App Script(在 javascript 中)编写了一个脚本,我正在寻找一种方法来最好地优化 function,它基于一个或多个搜索字段返回对象。 The data is stored in a Google Sheet.
数据存储在 Google 表格中。 The UI I have passes parameters to my function, then I iterate over a given sheet to find rows that meet a criteria, and add cells to an object, to be returned.
我将参数传递给 function 的 UI,然后我遍历给定的工作表以查找满足条件的行,并将单元格添加到 object,以返回。 The return could be just one object or a list of objects.
返回可能只是一个 object 或对象列表。 For the most part, this works fine, but if I have this type of function nested in a loop it can really drag the performance.
在大多数情况下,这工作正常,但如果我将这种类型的 function 嵌套在一个循环中,它确实会拖累性能。 Any advise on how to improve performance would be greatly appreciated.
任何关于如何提高性能的建议将不胜感激。 Here is an example of my code:
这是我的代码示例:
function GetAllReportByOrgID_DataLayer_(org_id, reporting_periods) {
//get all reporting period for program
var rows = GetDataRows_(DATA_SPREAD_SHEET_ID, RESPONSE_PAGE);
var surveys = [];
for (var i = 1; i < rows.length; i++) {
var row = rows[i];
var found_org_id = row[2];
var found_is_active = row[13];
if (found_org_id == org_id && found_is_active == true ) {
var survey = {};
survey.indicator_id = row[0];
survey.program_id = row[1];
survey.org_guid = row[2];
survey.survey_response = row[3];
survey.reporting_period = row[5];
survey.reporting_period_name = GetReportingPeriodNameById_(row[5], reporting_periods);
survey.is_final_report = row[6];
survey.is_submitted = row[7];
survey.submitted_by = row[8];
survey.submitted_by_email = row[9];
survey.date_created = ConvertUnixTimeStampToDateTime_(row[10]);
survey.date_updated = ConvertUnixTimeStampToDateTime_(row[11]);
survey.fiscal_year = row[12];
survey.documents = GetDocumentsById_DataLayer_({
program_id: row[13]
});
surveys.push(survey);
}
}
surveys.success = true;
return surveys;
}
function GetDataRows_(Sheet_Id, SheetName) {
var sheet = GetSheet_(Sheet_Id, SheetName);
var rows = [];
if (sheet) {
rows = sheet.getDataRange().getValues();
}
return rows;
}
function GetSheet_(Sheet_Id, SheetName) {
var ss = SpreadsheetApp.openById(Sheet_Id);
var sheet = ss.getSheetByName(SheetName);
return sheet;
}
function GetReportingPeriodNameById_(id, reporting_periods) {
if (id) {
for (var i = 0; i < reporting_periods.length; i++) {
if (reporting_periods[i].id == id) {
return reporting_periods[i].value
}
}
return "Reporting Period Not Found"
} else {
return "Reporting Period Not Found"
}
}
function GetDocumentsById_DataLayer_(data) {
var rows = GetDataRows_(DATA_SPREAD_SHEET_ID, PROGAM_DOCUMENTS_PAGE);
var documents = [];
var program_id = data.program_id.trim();
for (var i = 1; i < rows.length; i++) {
var row = rows[i];
var found_program_id = row[1];
var is_active = row[6];
if(is_active === true){
if (found_program_id === program_id) {
var document = {};
document.document_id = row[0];
document.program_id = row[1];
document.document_name = row[2];
document.file_id = row[3];
document.file_name = row[4];
document.file_url = row[5]
document.date_created = ConvertUnixTimeStampToDateTime_(row[7]);
document.date_updated = ConvertUnixTimeStampToDateTime_(row[8]);
documents.push(document);
}
}
}
documents.success = true;
return documents;
}
function ConvertUnixTimeStampToDateTime_(unix_timestamp) {
if (!unix_timestamp) {
return "";
}
var a = new Date(unix_timestamp * 1000);
var months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
var year = a.getFullYear();
var month = months[a.getMonth()];
var date = a.getDate();
var hour = a.getHours();
var min = a.getMinutes();
var sec = a.getSeconds();
var time = a.getMonth() + "/" + date + "/" + year + " " + hour + ":" + min + ":" + sec;
return time;
}
This code mostly works fine, except when it is in a loop that gets called 100 times or so, then things lag and can take a minute or more to process.这段代码大部分工作正常,除非它在一个被调用 100 次左右的循环中,然后事情会滞后,可能需要一分钟或更长时间来处理。 The sheets aren't that big, less that 200 rows and 15 columns.
工作表不是那么大,不到 200 行和 15 列。
thanks谢谢
The reason for performance depreciation is the GetDataRows_
function, because it makes repeated calls to Spreadsheet.openById()
, ss.getSheetByName(SheetName);
性能下降的原因是
GetDataRows_
function,因为它重复调用Spreadsheet.openById()
, ss.getSheetByName(SheetName);
. . You could try using a global
map
to cache these objects.您可以尝试使用全局
map
来缓存这些对象。 For example, Use a Spreadsheet
map例如,使用
Spreadsheet
map
const globalSSMap = new Map();//global SS map
Then your getter functions can be rewritten.然后你的 getter 函数可以被重写。 For eg, to get
ss
, use例如,要获取
ss
,请使用
if(!globalSSMap.has(Sheet_id)) globalSSMap.set(Sheet_id,SpreadsheetApp.openById(Sheet_Id));
var ss = globalSSMap.get(Sheet_id);
Data_Layer.gs数据层.gs
function GetAllDataByManager_DataLayer_(loggedin_user) {
var ss = SpreadsheetApp.openById(DATA_SPREAD_SHEET_ID);
var sheets = ss.getSheets();
// create sheet objects
var sheetData = {};
sheets.forEach(sheet => {
sheetData[sheet.getName()] = sheet.getDataRange().getValues();
})
var program_rows = sheetData[PROGRAM_MANAGERS];
var ip_ids = [];
var Company_data = [];
var runtimeCountStart = new Date();
//first search to make sure logged in user exists, and is marked as Active == True and is marked as an Admin
//if they exist, add their ID to the list
//Should only see records for the logged in user if
//they are either listed as the primary manager (company tab)
//or they are listed as an additional manager (program managers tab)
for (var i = 1; i < program_rows.length; i++) {
var row = program_rows[i];
var found_admin_email = row[2];
var found_is_active = row[10];
if (found_admin_email == loggedin_user && found_is_active == true) {
ip_ids.push(row[1])
}
}
var partner_rows = sheetData[PARTNER_PAGE];
for (var i = 1; i < partner_rows.length; i++) {
var partner_row = partner_rows[i]
var found_partner_id = partner_row[0];
var add_record = false;
if(ip_ids.includes(found_partner_id)){
add_record = true;
}else{
var found_cor_email = partner_row[5]
if(loggedin_user.toUpperCase() == found_cor_email.toUpperCase()){
add_record = true;
}
}
if(add_record == true){
var partner = {
ip_id: partner_row[0],
ip_name: partner_row[1],
ip_poc_name: partner_row[2],
ip_poc_email: partner_row[3],
manager_name: partner_row[4],
manager_email: partner_row[5],
is_active: partner_row[6],
date_created: partner_row[7],
created_by: partner_row[8],
partner_programs: GetAllProgramDataByIP_DataLayer_(sheetData, found_partner_id),
partner_notes: GetProgramNarrativesByPartnerID_DataLayer_(sheetData, found_partner_id),
partner_reports: GetAllReportByPartnerID_DataLayer_(sheetData, found_partner_id)
};
Company_data.push(partner)
}
}
stop = new Date();
newRuntime = Number(stop) - Number(runtimeCountStart);
newRuntime = (newRuntime /1000)/60
return Company_data;
}
function GetAllProgramDataByIP_DataLayer_(sheetData, ip_id) {
var rows = sheetData[PROGRAM_PAGE];
var programs = [];
for (var i = 1; i < rows.length; i++) {
var row = rows[i];
var found_partner_id = row[1];
var program = {}
if (found_partner_id === ip_id) {
program.program_id = row[0].toString();
program.partner_id = row[1].toString();
program.program_name = row[2].toString();
program.program_country = row[3].toString();
program.program_background = row[4].toString();
program.program_objectives = row[5].toString();
program.program_justification = row[6].toString();
program.program_start_date = row[7].toString();
program.program_status = row[8].toString();
program.program_contract_number = row[9].toString();
program.is_active = row[10]
program.date_created = ConvertUnixTimeStampToDateTime_(row[11].toString());
program.date_updated = ConvertUnixTimeStampToDateTime_(row[12].toString());
program.success = true;
programs.push(program)
}
}
return programs;
}
function GetProgramNarrativesByPartnerID_DataLayer_(sheetData, partner_id) {
var rows = sheetData[PROGRAM_NARRATIVE_NOTE];
var programs_notes = [];
var response = {};
for (var i = 1; i < rows.length; i++) {
var row = rows[i];
var found_partner_id = row[2];
var is_active = row[7];
if(is_active === true){
if (found_partner_id === partner_id) {
var note = {};
note.note_id = row[0];
note.program_id = row[1];
note.company_guid = row[2];
note.note_title = htmlEscape_(row[3]);
note.note_desc = htmlEscape_(row[4]);
note.note_reportingPeriod = row[5];
note.activity_theme = row[6];
note.date_created = ConvertUnixTimeStampToDateTime_(row[8]);
note.date_updated = ConvertUnixTimeStampToDateTime_(row[9]);
programs_notes.push(note);
}
}
}
response.success = true;
response.programs_notes = programs_notes
return response;
}
function GetAllReportByPartnerID_DataLayer_(sheetData, partner_id) {
//get all reporting period for program
var rows = sheetData[RESPONSE_PAGE];
var surveys = [];
for (var i = 1; i < rows.length; i++) {
var row = rows[i];
var found_partner_id = row[2];
if (found_partner_id == partner_id) {
var survey = {};
survey.indicator_id = row[0];
survey.program_id = row[1];
survey.company_guid = row[2];
survey.survey_response = row[3];
survey.reporting_period = row[5];
survey.is_final_report = row[6];
survey.is_submitted = row[7];
survey.submitted_by = row[8];
survey.submitted_by_email = row[9];
survey.date_created = ConvertUnixTimeStampToDateTime_(row[10]);
survey.date_updated = ConvertUnixTimeStampToDateTime_(row[11]);
survey.fiscal_year = row[12];
surveys.push(survey);
}
}
surveys.success = true;
return surveys;
}
Helper_Functions.gs Helper_Functions.gs
function ConvertUnixTimeStampToDateTime_(unix_timestamp) {
if (!unix_timestamp) {
return "";
}
var a = new Date(unix_timestamp * 1000);
var months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
var year = a.getFullYear();
var month = months[a.getMonth()];
var date = a.getDate();
var hour = a.getHours();
var min = a.getMinutes();
var sec = a.getSeconds();
var time = a.getMonth() + "/" + date + "/" + year + " " + hour + ":" + min + ":" + sec;
return time;
}
function CreateGUID_() {
return Utilities.getUuid();
}
function htmlEscape_(str) {
str = str.toString();
if (str && str.length > 0) {
return str.replace(/<[^>]+>/g, "")
} else {
return "";
}
}
GetDocumentsById_DataLayer_
and survey.documents
in the shared script.GetDocumentsById_DataLayer_
和survey.documents
。GetAllDataByManager_DataLayer_()
where nested loop occur when you are checking your partner_rows
variable.GetAllDataByManager_DataLayer_()
中寻找可以改进的地方,当您检查partner_rows
变量时会发生嵌套循环。Spreadsheet.openById()
, you still make individual calls when you map your sheet objects since you use ss.getSheetByName(SheetName);
Spreadsheet.openById()
,但由于您使用ss.getSheetByName(SheetName);
map 您的工作表对象时,您仍然会单独调用to get individual sheet object based on the SheetName
and even reading the sheet values during every loop for 3 different sheetsSheetName
,甚至在每个循环中读取 3 个不同工作表的工作表值getSheets()
, get its data range values then map them based on their sheet name.getSheets()
在电子表格中获取所有工作表 object ,获取其数据范围值,然后根据工作表名称获取 map 。 As what was suggested by @TheMaster in the other answerHelper_Functions.gs
Helper_Functions.gs
中不需要的函数
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.