Project

General

Profile

Feature #7366

improve performance of buffer.fill

Added by Constantin Asofiei 12 months ago. Updated 11 days ago.

Status:
WIP
Priority:
Normal
Target version:
-
Start date:
Due date:
% Done:

80%

billable:
No
vendor_id:
GCD

History

#1 Updated by Constantin Asofiei 12 months ago

Created branch 7366a from trunk rev 14573.

7366a/14574 contains a first attempt at improving performance of Buffer.fill. This gives ~1% improvement for a large app.

The main takeways/unknowns are:
  • BEFORE-TABLE management - should direct record access be disabled in this case? If yes, check if BEFORE-TABLE can be handled explicitly.
  • is the destination table in a FILL operation always a temp-table? If yes, then triggers can never be invoked. I'm not sure if other validation needs to be explicitly done.
  • replace Runnable lambdas with a Runnable instance and check performance (especially in processDataSource).

#2 Updated by Constantin Asofiei 12 months ago

  • % Done changed from 0 to 80

7366a rev 14575 contains the changes for FILL performance improvements. Extent is not added yet.

#3 Updated by Ovidiu Maxiniuc 12 months ago

Constantin Asofiei wrote:

Created branch 7366a from trunk rev 14573.

7366a/14574 contains a first attempt at improving performance of Buffer.fill. This gives ~1% improvement for a large app.

The main takeways/unknowns are:
  • BEFORE-TABLE management - should direct record access be disabled in this case? If yes, check if BEFORE-TABLE can be handled explicitly.

Yes, I think this can use direct access. All BEFORE-TABLE-s have a single, non-unique index. And, as with the other temp-tables, they do not have triggers to fire.

  • is the destination table in a FILL operation always a temp-table? If yes, then triggers can never be invoked. I'm not sure if other validation needs to be explicitly done.

Only temp-tables can be FILL-ed. In fact a temp-table must be first added to a dataset before this operation. The buffers of permanent tables cannot be components of a dataset.
I guess the only validation to be performed is null checking.

  • replace Runnable lambdas with a Runnable instance and check performance (especially in processDataSource).

Yes, extracting the independent lambdas as Runnable instance makes sense, but in my tests the gain is only 10% when the code to be executed is empty. Adding code to be executed will cause the gain to be unnoticeable.

#4 Updated by Constantin Asofiei 12 months ago

Ovidiu, BEFORE-TABLE is not involved during FILL, as TRACKING-CHANGES is not allowed for FILL. So there is no need manage the BEFORE-TABLE records.

About null validation: how do you mark a temp-table field as non-null in 4GL? MANDATORY doesn't work.

#5 Updated by Ovidiu Maxiniuc 12 months ago

I was pretty sure if you use

DEFINE TEMP-TABLE <name> LIKE <permanent-table-with-mandatory-fields>
the mandatory attribute is preserved for the new fields.

However, this does not happens. The corresponding fields from the new temp-table will be able to store ? value. I googled it and there is the following kb article:
https://community.progress.com/s/article/Is-it-possible-to-make-a-temp-table-field-mandatory.

Actually, this is a good news. We can simplify the Validation.validateMaybeFlush() method for temp-tables.

#6 Updated by Constantin Asofiei 12 months ago

rebased branch 7366a from trunk rev 14584 - new rev 14586.

#7 Updated by Constantin Asofiei 11 months ago

Branch 7366a was merged to trunk rev 14589 and archived. What's left is a possible improvement for extent fields.

#8 Updated by Constantin Asofiei about 1 month ago

Idea of improvements:
  • the data-source query may or may not use all record fields, depending on the mapping. We can use the FIELDS option to force populating only those fields.
  • try to create a FQL JOIN between the top and child buffer's data source queries, read all the records and cache them in a map on the 'join' condition.

#9 Updated by Constantin Asofiei 12 days ago

Changes related to this are in 8363g rev 15158: Allow the query to be reset to its initialization state, so the same instance can be used to execute child buffer FILL operations.

#11 Updated by Constantin Asofiei 12 days ago

Eric/Ovidiu: please review 8363g rev 15158.

#12 Updated by Ovidiu Maxiniuc 11 days ago

Review of 8363g, r15157/8.

I think I understand the idea: if the same query can be reused for a child buffer, it does not make sense to recreate it for each iteration of the parent buffer. So instead of close/open, we so a clearResult() instead. There one thing I am not sure I fully understand: the optimization is active only when the fill() is called for the parent database. Why not use this when an individual buffer is called? For example, a top-level-buffer with one or multiple children?

I see no other issues with the new code.

#13 Updated by Constantin Asofiei 11 days ago

Ovidiu Maxiniuc wrote:

I think I understand the idea: if the same query can be reused for a child buffer, it does not make sense to recreate it for each iteration of the parent buffer. So instead of close/open, we so a clearResult() instead. There one thing I am not sure I fully understand: the optimization is active only when the fill() is called for the parent database. Why not use this when an individual buffer is called? For example, a top-level-buffer with one or multiple children?

You are right, I need to add a fillInt method to be called from the main Buffer.fill and for the child-buffer FILL in processDataSource. I'll see how I can change these.

Also available in: Atom PDF