This question already has answers here:
Formulas make SpreadsheetApp work slower in Google Sheets Script
(3 answers)
Random slowness of Google Spreadsheet scripts
(1 answer)
Unreasonably slow apps script when accessing data from a google sheet cell
(2 answers)
Why my Google App Scripts slow down over time?
(2 answers)
Closed 2 months ago.
I have a simple appscript that fetches the first row from a data sheet and populate it into another sheet in the same worksheet. It is usually executed within 1-3 secs.
From last few days I am observing that the script take a long time at getSheetByName() for the first sheet. Once the first sheet is executed the next sheet does not take time. The below logs shows it took more than 90 secs just to execute getSheetByName() for the first sheet (Calling Dashboard). The second sheet is executed almost instantaneously with the rest of the script. This is happening randomly after several executions and it is affecting our work.
I have tried SpreadsheetApp.flush(); but that does not help when this happens.
I am wondering if there a better way of handling this or I have missed anything? I have gone through several online resources but could not find any guidance on this kind of issue.
I am attaching my script and any help will be very much appreciated!!
enter image description here (Logs snapshot attached)
function fetchNextCallBack() {
Logger.log("Start Function")
const myGooglSheet = SpreadsheetApp.getActiveSpreadsheet();
Logger.log("Active Spreadsheet initiated")
//SpreadsheetApp.flush();
const shUserForm = myGooglSheet.getSheetByName("Calling Dashboard");
Logger.log("Calling Dashboard Initiated")
const datasheet = myGooglSheet.getSheetByName("Call Backs");
Logger.log("Call Backs Initiated")
shUserForm.getRange("C8:C22").clearContent();
shUserForm.getRange("F10:F18").clearContent();
shUserForm.getRange("M4:M6").clearContent();
Logger.log("Dashboard cleared")
const values = datasheet.getRange("A3:N3").getValues();
Logger.log("Call back Data fetched")
shUserForm.getRange("C8").setValue(values[0][5]); // vehicle no
shUserForm.getRange("C10").setValue(values[0][3]); // mobile no
shUserForm.getRange("C12").setValue(values[0][2]); // customer name
shUserForm.getRange("F12").setValue(values[0][4]); // model
shUserForm.getRange("C14").setValue(values[0][1]); // call type
shUserForm.getRange("F14").setValue(values[0][6]); // service type
shUserForm.getRange("F20").setValue(values[0][13]); // cre
shUserForm.getRange("C18").setValue(values[0][11]); // appt date
shUserForm.getRange("F18").setValue(values[0][12]); // appt slot
shUserForm.getRange("F10").setValue("REMINDER CALL");
Logger.log("Call back Data populated in dashboard")
}
the script is expected to be completed within 1-3 secs. However it takes sometime more than 90 secs abruptly. It always get stuck in the following line:
getSheetByName()
The code you show seems fine. Chances are that the spreadsheet is on the heavy side, and that makes accessing the data slow. You can confirm whether that is the case by making a copy of the spreadsheet and deleting everything on every tab, leaving say 25 blank rows on each tab. Then test the code in the blank spreadsheet and see if the same thing happens.
To improve spreadsheet performance, see these optimization tips.
Related
If I am using the Script Recording and Playback feature on same transaction for instance ME25, multiple times, I am getting cumulative data as part of multiple scripts rather than incremental data.
Explanation :
If I open ME25 details and enter "100-310" as Material and "Ball Bearing" as Short Text and stop the recording, I get the following script, which is expected behavior.
session.findById("wnd[0]/usr/tblSAPMM06BTC_0106/ctxtEBAN-MATNR[3,0]").text = "100-310"
session.findById("wnd[0]/usr/tblSAPMM06BTC_0106/txtEBAN-TXZ01[4,0]").text = "Ball Bearing"
session.findById("wnd[0]/usr/tblSAPMM06BTC_0106/txtEBAN-TXZ01[4,0]").setFocus
session.findById("wnd[0]/usr/tblSAPMM06BTC_0106/txtEBAN-TXZ01[4,0]").caretPosition = 12
After this, I restart the recording and type Qty Requested as "100" and delivery date as "21.04.2021" and stop the recording. I get the following script:
session.findById("wnd[0]").maximize
session.findById("wnd[0]/usr/tblSAPMM06BTC_0106/ctxtEBAN-MATNR[3,0]").text = "100-310"
session.findById("wnd[0]/usr/tblSAPMM06BTC_0106/txtEBAN-TXZ01[4,0]").text = "Ball Bearing"
session.findById("wnd[0]/usr/tblSAPMM06BTC_0106/txtEBAN-MENGE[5,0]").text = "100"
session.findById("wnd[0]/usr/tblSAPMM06BTC_0106/ctxtRM06B-EEIND[8,0]").text = "21.04.2021"
session.findById("wnd[0]/usr/tblSAPMM06BTC_0106/ctxtEBAN-EKGRP[9,0]").setFocus
session.findById("wnd[0]/usr/tblSAPMM06BTC_0106/ctxtEBAN-EKGRP[9,0]").caretPosition = 0
Instead of getting the incremental part that I typed for the second recording instance, I am getting complete script. Is there a way to achieve incremental scripts?
I can reproduce in my SAP GUI 7.60 (whatever screen it is; whatever kind of field it is, I can reproduce even with very simple fields like in a Selection Screen).
It seems that it happens all the time, even if you write your own recorder (a VBS script which mainly uses session.record = True + event handlers). It's due to the fact that SAP GUI sends all the screen events (i.e. the user actions) since the screen was entered, when the user presses a button, a function key, closes a window, or stops the SAP GUI Recorder.
If you write your own recorder, I guess you can save the screen contents when you start the recorder, and when the "change" events occur you may ignore those ones where the new field value has not changed since the recorder started. But that's a lot of work.
I think that it's far more easy to append manually the last lines of the last script to the initial script.
my issue is that I want to be able to get two time stamps and compare if the second (later taken) one is less than 59 minutes away from the first one.
Following this thread Compare two dates with JavaScript
the date object may do the job.
but first thing i am not happy with is that it takes the time from my system.
is it possible to get the time from some public server or something?
cause there always is a chance that the system clock gets manipulated within the time stamps, so that would be too unreliable.
some outside source would be great.
then i am not too sure how to get the difference between 2 times (using 2 date objects).
many issue that may pop up:
time being something like 3:59 and 6:12
so just comparing minutes would give the wrong idea.
so we consider hours too.
biut there the issue with the modulo 24.
day 3 23:59 and day 4 0:33 wouldnt be viewed proper either.
so including days too.
then the modulo 30 thing, even though that on top changes month for month.
so month and year to be included as well.
so we would need the whole date, everything from current year to second (because second would be nice too, for precision)
and comparing them would require tons of if clauses for year, month, etc.
do the date objects have some predfeined date comparision function that actually keeps all these things in mind (havent even mentioned leap years yet, have I)?
time would be very important cause exactly at the 59 minutes mark (+-max 5 seconds wouldnt matter but getting rmeitely close to 60 is forbidden)
a certain function would have to be used that without fail closes a website.
script opens website at mark 0 min, does some stuff rinse and repeat style and closes page at 59 min mark.
checking the time like every few seconds would be smart.
Any good ideas how to implement such a time comparision that doesnt take too more computer power yet is efficient as in new month starting and stuff doesnt mess it up?
You can compare the two Date times, but when creating a date time there is a parameter of DateTime(value) which you can use.
You can use this API to get the current UTC time which returns a example JSON array like this:
{
"$id":"1",
"currentDateTime":"2019-11-09T21:12Z",
"utcOffset":"00:00:00",
"isDayLightSavingsTime":false,
"dayOfTheWeek":"Saturday",
"timeZoneName":"UTC",
"currentFileTime":132178075626292927,
"ordinalDate":"2019-313",
"serviceResponse":null
}
So you can use either the currentFileTime or the currentDateTime return from that API to construct your date object.
Example:
const date1 = new Date('2019-11-09T21:12Z') // time when I started writing this answer
const date2 = new Date('2019-11-09T21:16Z') // time when I finished writing this answer
const diff = new Date(date2-date1)
console.log(diff.toTimeString()) // time it took me to write this
Please keep in mind that due to network speeds, the time API will be a little bit off (by a few milliseconds)
My problem is that I see the load time for a web page element on a test in jMeter # 200 miliseconds and when browsing, most of the time I get 3 or 4 seconds, in the condition where the size in bytes is # 331000.
I must mention that I cleared the cache and cookies for each iteration and I inserted also the constant timer between the steps.
The searching an id is the actual case described previously.
var pkg = JavaImporter(org.openqa.selenium);
var wait_ui = JavaImporter(org.openqa.selenium.support.ui.WebDriverWait);
var wait = new wait_ui.WebDriverWait(WDS.browser, 5000);
WDS.sampleResult.sampleStart()
var searchBox = WDS.browser.findElement(pkg.By.id("140:0;p"));
searchBox.click();
searchBox.sendKeys("1053606032");
searchBox.sendKeys(org.openqa.selenium.Keys.ENTER);
WDS.sampleResult.sampleEnd()
I expected to see the same load time results, but maybe an option would be if I wait until some elements on the search results page are visible. But I cannot bring an argument why is this difference. I had another case where the page loads in 10 seconds in Chrome and in jMeter Test Results 300 miliseconds.
Please try with wait until for a specific element which loads as close as the page load.
Below is another try for the same. Use the below code and check if this helps:-
WDS.sampleResult.sampleStart()
WDS.browser.get('http://jmeter-plugins.org')
//(JavascriptExecutor)WDS.browser.executeScript("return document.readyState").toString().equals("complete")
WDS.browser.executeScript("return document.readyState").toString().equals("complete")
WDS.sampleResult.sampleEnd()
For me without execute script page loads in 3 sec and with executeScript it loads in 7 sec..while in browser that loads in around 7.57sec..
Hope this helps.
I've seen developers have had this problem since a few years ago. I have studied many forums and the official POI documents. Nonetheless I haven't found an answer yet.
So the problem is.. I have tried the following two snippets:
Workbook wb = WorkbookFactory.create(new File("spreadsheet.xlsx"));
and
File file = new File("C:\\spreadsheet.xlsx");
OPCPackage opcPackage = OPCPackage.open(file.getAbsolutePath());
XSSFWorkbook workbook = new XSSFWorkbook(opcPackage);
and either of the approaches takes about 5-6min (if the application doesn't run out of memory) to process a simple and fairly small spreadsheet.xlsx file (200KB).
What do I need to do to fix this? (I'm using Apache POI 3.9)
/*****************************/
The process takes a long time in the following location:
public class XSSFSheet extends POIXMLDocumentPart implements Sheet{
...
protected void read(InputStream is) throws IOException {
try {
-->>> worksheet = WorksheetDocument.Factory.parse(is).getWorksheet();
} catch (XmlException e){
throw new POIXMLException(e);
}
}
...
I can't debug further. The VisualVM also says the same thing..!
One factor that might be contributing to the load time is that the data has been pasted into the worksheet so that the used range includes every row, ie when you use the sheet.usedrange rows count it returns > 1,000,000 rows.. Not sure how this happens but I found that I needed to perform an intermediary step wherein prior to loading the workbook I 'cleaned' it by using some vba script. The workbook has around 20 sheets of around 5000 rows each, each of which are filled out by different parts o the business, and it takes a fairly long time (maybe 4 minutes) to load but that is acceptable in this case. Before I added the cleaning stage it ran for over 30 minutes, which was not acceptable....
A user runs the process I am referring to, bu pressing two buttons. The first cleans, the second does the rest. The first process is triggered using Runtime.getruntime.exec and creates an empty text file that the second process will not run unless the test file is there.
I have a mobile app that is using LinqToDatasets to update/insert into a SQL Server CE 3.5 File.
My Code looks like this:
// All the MyClass Updates
MyTableAdapter myTableAdapter = new MyTableAdapter();
foreach (MyClassToInsert myClass in updates.MyClassChanges)
{
// Update the row if it is already there
int result = myTableAdapter.Update(myClass.FirstColumn,
myClass.SecondColumn,
myClass.FirstColumn);
// If the row was not there then insert it.
if (result == 0)
{
myTableAdapter.Insert(myClass.FirstColumn, myClass.SecondColumn);
}
}
This code is used to keep the hand held database in sync with the server database. Problem is if it is a full update (first time for example) there are a lot of updates (about 125). That makes this code (and more loops like it take a very long time (I have three such loops that take over 30 seconds each).
Is there a faster or better way to do updates/inserts like this?
(I did see this Codeplex Project, but I could not see how to make it work with both updates and inserts.)
You should always use SqlCeResultSet for data access on mobile devices for maximum performance and memory usage. You must identify the data to be inserted and then use code like the SqlCeBulkCopy sample, and use similar code by using the Seek and Update methods of the SqlCeResultSet.