Improving join performance for queries with FIRST or LAST criteria
- Last Updated: February 11, 2026
- 2 minute read
- OpenEdge
- Version 13.0
- Documentation
In versions prior to Progress OpenEdge 11.7.4, processing an ABL join query with multiple tables using the FIRST or LAST keywords was significantly slow as compared to processing a similar ABL query against a single table or against a join query that did not use FIRST or LAST criteria. This happened because the server join was unable to reduce the FIRST or LAST criteria to a single server join record during ABL to SQL translation which led to a widened result set and forced client selection, in some cases, the client was forced to retrieve server records key by key using multiple queries.
The join performance has now been improved by ensuring that all joins with FIRST or LAST criteria translate ABL to a single server join SQL statement. This functionality is known as Single-shot functionality.
- Maximizing server optimization
- Minimizing client selection
- Reducing round trips to the foreign data source
An example of single-shot at innermost join level is shown below. Here, single-shot is at innermost join level and remaining buffers are joined using EACH statement. It will be evaluated at server side.
FOR EACH customer,
EACH order OF customer,
EACH orderline OF order,
FIRST ITEM OF orderline:
DISPLAY customer.custnum order.custnum order.ordernum
orderline.linenum item.itemnum.
END.
The ABL uses an index to evaluate the “FIRST” or “LAST” criteria. By default, the primary index is selected in determining the “MIN” or “MAX” column criteria to be applied in the server sub-query that handles the FIRST or LAST join criteria. When USE-INDEX clause is used, the index specified in the USE-INDEX clause will be used in place of the default primary index.
Index definitions support ABL USE-INDEX
modifier. ABL translates USE-INDEX to ORDER BY for DataServer operations. For example, if you
define custnum as an index on the custnum field without using the single shot query
mechanism, the following ABL statements are equivalent when accessing a SQL database:
|
|
The following examples illustrate the behavior of the index definition if the single-shot query mechanism is used.
If single-shot query mechanism is used, the following query results in a server-side join:
|
If the single-shot query mechanism is used, the following query results in a
client-side join as the BY clause has been used:
|
If you do not specify USE-INDEX,
your query will return records in an unpredictable order. Your application might not
require predictable ordering, but if it does, be sure to include USE-INDEX in your query definition.
Progress recommends that you use a unique index as a USE-INDEX modifier when using it with a FOR
EACH query that joins FIRST or LAST on a child table. If the index is not unique, join
is still evaluated on client side.
Client startup parameter and QUERY-TUNING Switch
Single-shot evaluation on server will be ON by default. It can be turned OFF
and evaluated at client side by using client startup parameter -nojoinbysqldb. It can also be turned OFF at run time with QUERY-TUNING
switch NO-JOIN-BY-SQLDB.