Understanding the Synergy Select API

The Select API enables you to perform SQL-like queries to retrieve and update Synergy DBMS data. By providing an optimized way to read and filter data, the Select API offers an opportunity to improve application performance, especially across a network.

The Select class object (Synergex.SynergyDE.Select.Select) is the foundation of the Select API. It requires a From class object, which defines where the data is coming from and what the data looks like. You can also optionally do the following:

The above class objects perform queries to retrieve data on individual Synergy DBMS files, but you can combine records from two or more files using the Join method in the Select class, along with the JoinSelect, RowEnumerator, Rows, and On class objects. (See Joining data from multiple sources for more information.)

Important

Once created, the From, Where, NoCaseWhere, GroupBy, NoCaseGroupBy, On, OrderBy, NoCaseOrderBy, and Sparse objects must remain in contact with the same records specified in the From objects as well as fields referenced in the Where, NoCaseWhere, GroupBy, NoCaseGroupBy, On, OrderBy, NoCaseOrderBy, and Sparse objects that are contained in the records. In other words, you can’t create one of these objects and pass it to another routine unless that routine has direct access to the original record. If this is not the case, an InvalidOperationException or $ERR_INVOPER error (“Where operator requires at least one field reference”) will result when creating the Select object. On the other hand, all data references outside a From object’s record are copied during the object’s creation and are not required to remain in contact with the original data.

You can also use the Select API to do the following:

Joining data from multiple sources

You can combine data from multiple Synergy DBMS sources by using the Select Join feature. The Select Join feature identifies records from two or more files (aka tables in SQL) to join, providing functionality similar to SQL92’s high-speed inner joins and left outer joins.

Note

The SQL terms “table,” “row,” and “column” are equivalent to the Synergy terms “file,” “record,” and “field,” respectively. In the Synergy/DE documentation, we use the latter terminology.

For example, say you wanted a list of all customers in the customer file and whether each customer had any orders during a particular period, defined by start and end dates. Here’s how you could do that:

1. Each source file must contain one or more matching fields for which a join can be made. The matching fields must be of the same type and size, unless both field and key type are numeric. For example,
fromOrders = new From("orders.ism", orders)
fromOrderdetails = new From("orderdetails.ism", orderdetails)
fromCustomers = new From("customers.ism", customers)
fromProducts = new From("products.ism", products)
2. Match up the Orders file with the Orderdetails file. For each order there are one or more details, but you want to see only the details that are covered in the Orders file. The Orders file and the Orderdetails file both contain the matching field OrderID.
joinObj = new Select( fromOrders.InnerJoin( fromOrderdetails, 
&         (On)(orders.OrderID == orderdetails.OrderID) ) ).Join()
3. Here are some ways to link up customers and orders:
joinObj = new Select( fromOrders
&         .InnerJoin( fromOrderdetails,
&         (On)(orders.OrderID == orderdetails.OrderID))
&         .InnerJoin( fromCustomers,
&         (On)(orders.CustomerID == customers.CustomerID))
&         .InnerJoin( fromProducts,
&         (On)(orderdetails.ProductID == products.ProductID)))).Join()
foreach rows in new Select(new From("orders.ism", order)
&         .InnerJoin(new From("orderdetails.ism", orderdetails),
&         (On)(orders.OrderID == orderdetails.OrderID))
&         .InnerJoin(new From("customers.ism", customers),
&         (On)(orders.CustomerID == customers.CustomerID))
&         .InnerJoin(new From("products.ism", products),
&         (On)(orderdetails.ProductID == products.ProductID)))).Join()
foreach rows in new Select( fromCustomers
&       .InnerJoin( fromOrders,
&       (On)(customers.CustomerID == orders.CustomerID .AND.
&       (orders.OrderDate .GE. StartDate .AND.
&       orders.OrderDate .LE. EndDate)).Join()
foreach rows in new Select( fromOrders
&       .InnerJoin( fromCustomers,
&       (On)(customers.CustomerID == orders.CustomerID)),
&       (Where)(orders.OrderDate .GE. StartDate .AND.
&       orders.OrderDate .LE. EndDate)).Join()
foreach rows in new Select( fromCustomers
&       .LeftJoin( fromOrders,
&       (On)(customers.CustomerID == orders.CustomerID .AND.
&       (orders.OrderDate .GE. StartDate .AND.
&       orders.OrderDate .LE. EndDate)).Join()
foreach rows in new Select( fromOrders
&       .LeftJoin( fromCustomers,
&       (On)(customers.CustomerID == orders.CustomerID .AND.
&       (orders.OrderDate .GE. StartDate .AND.
&       orders.OrderDate .LE. EndDate)).Join()
4. Iterate over the Join class object to retrieve the record set that matches. On the completion of each iteration, the Orders record and Orderdetails record are embedded in the Rows object. Use the Rows.Fill() method to extract them to their appropriate data records.
foreach rows in joinObj
  begin
    rows.fill(orders)
    rows.fill(orderdetails)
    .
    .
    .
  end
Note

If the first file specified on a join is remote on a server, you can only join other files on that same server. However, if the first file is local, you can join any local or remote files.

Optimizing your selections

Enabling Select debugging helps you determine how to optimize a Select statement by logging optimization details. You can turn on debugging for the Select class by setting the DBG_SELECT environment variable. You can use the DBG_SELECT_FILE environment variable to designate where the output will be written. The DBG_SELECT_INTERNAL environment variable locates Select statements that don’t optimize, or don’t optimize on the primary key, due to a type mismatch.

For additional information, see Optimization and ordering for ISAM files as well as the following articles on the Synergex Blog:

Prefetching records to improve performance with xfServer

To improve record selection performance when using xfServer, a prefetch feature is available that enables the client to prefetch (or buffer) selected records for files of any type that are open in input mode. Prefetching is off by default unless you’re using Join. To turn prefetching on, set the SCSPREFETCH environment variable to a value between 1 and 32, which specifies the size of the prefetch buffer in kilobytes. To turn prefetching off, set SCSPREFETCH to 0. You can enable or disable prefetching on a file-by-file basis by using the SETLOG routine to set or clear SCSPREFETCH before opening the channel specified in the From. The value of SCSPREFETCH is checked on every remote file open.