Server-side join processing
- Last Updated: October 21, 2024
- 5 minute read
- OpenEdge
- Version 12.2
- Documentation
Server-side join is a feature in which certain queries involving joins, execute on the database server, rather than the client. Server-side join improves performance by reducing the amount of data transferred across the network and by reducing the computational cost on the client.
Background
Prior to OpenEdge 12.0, when the AVM executed a join of multiple tables, some records which did not satisfy all levels of the join may have been returned to the AVM client, which needed to perform additional processing to eliminate these extra records from consideration. This methodology provided a correct response to the ABL application but with performance and security challenges. Starting in 12.0, incremental functionality was added to perform joins of multiple tables on the database server. This functionality is known as server-side join.
Requirements for server-side join use
The following requirements must be met for a join query to be executed server-side:
- The database server must be multi-threaded.
- All tables to be joined must be in the same logical database.
- There must be ten or fewer tables to be joined.
NO-LOCKmust be used.- The ABL query construct must be one of the following:
FORstatement.- Dynamic query that does not use the
INDEXED-REPOSITIONoption or involve an outer join.
NO-LOCK for server-side join to be in effect,
you can obtain records with a lock using the GET
statement for a static query, or the desired GET
method (for example, GET-NEXT()) for a dynamic
query.Restrictions
If all the requirements are met, there may still be some cases where server-side join is not used.
- Server-side join is not used for static queries (
DEFINE QUERYstatement). - Server-side join is not used for queries with the following
constructs on any child table:
- User-defined functions, methods, or properties with a
GETimplementation. CAN-DOfunction.- Expressions with MEMPTR and LONGCHAR data types.
TENANT-WHEREclause.
- User-defined functions, methods, or properties with a
- The use of
RECIDandROWIDto join records disables server-side join. - If a
FOR EACHquery contains aBYclause and the index used for the query provides the same sorting order specified theBYclause, the join in done on the server. However, if the table does not contain any indexes that provide the sorting specified by theBYclause, and theBYclause does not specify only fields for the most inner table of the join, then the join is done on the client.Note: You can tell whether the sort was done by index or not by looking at the "Client Sort:" entry in the query information log file (see Query plan). "Client Sort: Y" indicates a non-index sort and "Client Sort: N" indicates the sort was done by index.The following table shows different query examples and whether the join is executed on the server (On) or the client (Off).
Query example Server-side join Sort by index Notes FOR EACH Customer NO-LOCK, EACH Order OF Customer NO-LOCK, EACH OrderLine NO-LOCK OF Order BY OrderLine.Price : DISPLAY Customer.NAME OrderLine.Price Order.Carrier. END.On No Using the BYclause on the last table’s field – server-side join is always turned on.FOR EACH Customer NO-LOCK, EACH Order OF Customer NO-LOCK, EACH OrderLine NO-LOCK OF Order BY Customer.Address : DISPLAY Customer.NAME OrderLine.Price Order.Carrier. END.Off No Using the BYclause on the top parent table's field that results in non-index sorting causes server-side join to be turned off.FOR EACH Customer NO-LOCK, EACH Order OF Customer NO-LOCK, EACH OrderLine NO-LOCK OF Order BY Customer.NAME : DISPLAY Customer.NAME OrderLine.Price Order.Carrier. END.On Yes Using the BYclause on the top parent table field that results in index sorting causes server-side join to be turned on.FOR EACH Customer NO-LOCK, EACH Order OF Customer NO-LOCK, EACH OrderLine NO-LOCK OF Order BY Order.Carrier : DISPLAY Customer.NAME OrderLine.Price Order.Carrier. END.Off No Using the BYclause on any middle table field that results in non-index sorting causes server-side join to be turned off.
Server-side join (-ssj) startup parameter
You may want to run some queries with server-side join enabled and disabled, to compare differences in performance. Server-side join can be disabled by using the Server-side join (-ssj) database server startup parameter, when you start the database up. You specify a value of "0" to disable it:
|
Logging
To see if a particular query was done in the server, you can enable Query Information Logging for your client session. For example, start the client session using these startup parameters:
|
If the query was resolved in the database server, you see
"Server-side join" in the log file entry. For example, for a FOR statement, you see:
|
For a dynamic query, you see:
|
Notes
- If server-side join is enabled and the join query
contains a variable in the
WHEREclause, that variable should not be updated inside theFORblock, as changes to the variable's value are not communicated to the server after the join is initially sent by the client. If you do update a variable, then the results returned may not be as expected.The following example shows such a case:
FOR EACH Customer NO-LOCK, EACH Order OF Customer NO-LOCK WHERE order-date > myDateVar: ... myDateVar = new-value. END.To avoid this behavior, separate the inner join into its own innerFORblock to have the client perform the join. For example:FOR EACH Customer NO-LOCK: FOR EACH Order OF Customer NO-LOCK ... - When a join query executes, there is no guarantee that any child table buffers
of a join are released unless the record of its immediate parent table is
fetched. With server-side join enabled, because the server only sends records
that satisfies all levels of the join, you may see that a record that used to be
released on a child table is no longer released. Therefore, if no records
satisfy the query, then the child buffers are left in scope. For example:
If there are noFIND FIRST Order. FOR EACH Customer WHERE Cust-num < 10 NO-LOCK, EACH Order of Customer NO-LOCK.Customerrecords that satisfy theWHEREclause, then theOrderrecord remains in scope, whether server-side join is involved or not. If there areCustomerandOrderrecords that satisfy the query, then theOrderrecord in scope is released. When server-side join is not enabled, the ABL client drives the resolution of the join so the client needs to retrieve a record from the parent level before trying to find records in its child table, in which case it does release theOrderrecord. For this reason, it is not recommended that you depend on the availability of a record of a child table in a join after the join is executed.