Hi,
We have a situation wherein we are getting data from an external table. The scenario is we are filtering that external table to our local outsystems table thru the External ID column to check if that record exists in our local table and if not we'll create a new one. We are dealing with large amount of data in this process. We want to know which option is the most optimized when dealing with this kind of situation.
Reference: GetCategories is the external table
Option 1 - Loop thru the external table and filter the record one by one:
Option 2 - Get both the external and local table first then use the ListFilter action in the loop.
Option 3 - Create a server action function that cache the local table for 20 mins and call it in the loop.
Function:
Called inside the CreateUpdate
Let me know if you have some questions.
Thank you!
Hi Kim,
if we are talking of many, but really many records what we have implemented and we are very satisfied is done in two steps.
On your case what matters is the loading the DB.
The option we made is, when filtering the records we write it to a csv file.
After that we load the DB and it is very fast, think about that.
Regards
Option 1 is not recommended as per the best practice, as it will bring avoid unnecessary trips to the database: https://success.outsystems.com/documentation/11/building_apps/data_management/data_operations/best_practices_for_fetching_data/.
Therefore, I recommend Option 2 which uses filter in corresponding aggregate.
Older posts with similar questions:
https://www.outsystems.com/forums/discussion/93557/external-sql-server-database/
@Kim Tubice : I have an entirely different proposal for you and this without loops
Notes :
Concurrency Risk: This approach introduces a temporary entity (categories_temp), which can cause issues in parallel calls since the data isn't session-specific. To mitigate this, add a unique session identifier field (e.g., SessionId) to differentiate records per call.
Batch Processing: It’s advisable to perform the sync in batches instead of processing the entire dataset in a single operation. This helps manage memory and database locks more efficiently.
Hi Siya,
In relation to the Bulk Insert, do you do it with the Forge component BulkInsert or is there a way to run it directly in SQL?If executing it in SQL, could you give us a hint on how to build the SQL statement?
I have used the Bulk Insert forge component. Basically when you execute the GetCategories_Exeternal data has already comes to the front end server and the efficient method to put it to OutSystems database is using this Forge Component.
If you have direct access to the OutSystems database ( On premise installation) you can get the data from the other external database and insert data directly on to a temp table and execute the merge query. However you need to find about the exact physical table name from the System->Entity for the Local Category in your module.
Hi Siya, thank you for the insight. We are thinking of applying the bulk insert you mentioned and I have a question again. Which is more optimized, placing the bulk insert in option 2 before the loop or in the option 3 server action? The option 3 has a function to help with the memory load.
Using bulk insert is beneficial but looping there after will not yield you good result as there are many database operations happening in the loop. I have provided a MERGE SQL statement in the screenshot which you can utilise to optimise your logic instead of looping.
Hi @Kim Tubice ,
Please find the below 2 solutions.
Solution 1 :
Create a server action (e.g., GetCachedLocalCategories):
Fetch the local categories with caching enabled (Cache in Minutes = 20).
Output the list of ExternalIDs only (or a map/dictionary if you need fast lookup).
In the main CreateUpdate logic:
Loop through GetCategories (external data).
For each item, use a ListFilter or lookup in a local map/dictionary to check existence.
If not found, add it to a bulk create list.
At the end of the loop, use a Bulk Insert/Create if possible.
Solution 2 :
Use a Set-Based Approach with a Batch Insert
Instead of looping, let the database do the heavy lifting by using a set-based operation.
Fetch all External IDs from GetCategories.
Fetch all existing External IDs from the local table.
Use a server-side logic to calculate the difference (External IDs not in Local).
Batch insert only the new records.
You can do this with an aggregate or advanced SQL inside a Server Action:
SELECT E.*
FROM GetCategories E
LEFT JOIN LocalCategories L ON E.ExternalID = L.ExternalID
WHERE L.ExternalID IS NULL
Then insert the results into the local table in one go.
Hope this works.
Thanks,
Senthil