Most SQL statements have an associated Query Plan. A query plan is created when an SQL statement is prepared. By default, operations such as adding an index and recompiling the class purge this Query Plan. The next time the query is invoked it is re-prepared and a new Query Plan is created. Frozen plans enable you to retain (freeze) a existing Query Plan across compiles. Query execution uses the frozen plan, rather than performing a new optimization and generating a new query plan.
Changes to system software may also result in a different Query Plan. Usually, these upgrades result in better query performance, but it is possible that a software upgrade may worsen the performance of a specific query. Frozen plans enable you to retain (freeze) a Query Plan so that query performance is not changed (degraded or improved) by a system software upgrade.
How to Use Frozen Plans
There are two strategies for using frozen plans — the optimistic strategy and the pessimistic strategy:
Optimistic: use this strategy if your assumption is that a change to the system software or to a class definition will improve performance. Run the query and freeze the plan. Export (backup) the frozen plan. Unfreeze the plan. Make the software change. Re-run the query. This generates a new plan. Compare the performance of the two queries. If the new plan did not improve performance, you can import the prior frozen plan from the backup file.
Pessimistic: use this strategy if your assumption is that a change to the system software or to a class definition will probably not improve performance of a specific query. Run the query and freeze the plan. Make the software change. Re-run the query with the %NOFPLAN keyword (which causes the frozen plan to be ignored). Compare the performance of the two queries. If ignoring the frozen plan did not improve performance, keep the plan frozen and remove %NOFPLAN from the query.
Caché Version Upgrade Automatically Freezes Plans
When you upgrade Caché to a new major version, existing Query Plans are automatically frozen. This ensures that a major software upgrade will never degrade the performance of an existing query. After a software version upgrade, perform the following steps for performance-critical queries:
Execute the query with the plan state as Frozen/Upgrade and monitor performance. This is the optimized Query Plan that was created prior to the software upgrade.
Add the %NOFPLAN keyword to the query, then execute and monitor performance. This optimizes the Query Plan using the SQL optimizer provided with the software upgrade. It does not unfreeze the existing Query Plan.
Compare the performance metrics.
If the %NOFPLAN performance is better, the software upgrade improved the Query Plan. Unfreeze the Query Plan. Remove the %NOFPLAN keyword.
If the %NOFPLAN performance is worse, the software upgrade degraded the Query Plan. Keep the Query Plan frozen; promote it from Frozen/Upgrade to Frozen/Explicit. Remove the %NOFPLAN keyword.
After testing your performance-critical queries, you can unfreeze all remaining Frozen/Upgrade plans.
This automatic freeze occurs when you prepare/compile a query under a Caché version newer than the version under which the plan was originally created. For example, consider an SQL statement that was prepared/compiled under Caché version 2016.2. You then upgrade Caché to version 2017.1, and the SQL statement is prepared/compiled again. The system will detect this is the first prepare/compile of the SQL statement on the new version, and automatically marks the plan state as Frozen/Upgrade, and uses the existing plan for the new prepare/compile. This ensures the query plan used is no worse than the query plan of the previous version.
Only major version Caché upgrades automatically freeze existing query plans. The earliest upgrade that performs this operation is an upgrade from 2016.2.0. For example, a major version upgrade, such as from 2016.2 to 2017.1, or from 2017.1 to 2017.2 performs this operation. A maintenance release version upgrade, such as 2017.1.0 to 2017.1.1 does not perform this operation.
In the Management Portal SQL interface the SQL Statements Plan State column indicates these automatically frozen plans as Frozen/Upgrade and the Plan Version indicates the Caché version of the original plan. Refer to SQL Statement Details for further information. You can unfreeze individual plans using this interface.
You can list all Frozen/Upgrade plans in the current namespace using the INFORMATION.SCHEMA.STATEMENTS Frozen=2 property.
You can use the FreezePlans() method to freeze or unfreeze a single plan or multiple plans:
FreezePlans() can unfreeze Frozen/Upgrade query plans within the specified scope: namespace, schema, relation (table), or individual query.
FreezePlans() can promote (“freeze”) query plans flagged as Frozen/Upgrade to Frozen/Explicit. Commonly, you would use this method to selectively promote appropriate Frozen/Upgrade plans to Frozen/Explicit, then unfreeze all remaining Frozen/Upgrade plans.
An upgrade from Caché version 2016.2 to a later version does not change INSERT ... SELECT query plans to Frozen/Upgrade. If the plan state was Unfrozen, the plan state for these statements will remain Unfrozen. If the plan state was Frozen, the plan will be put in an error state and will be unusable; you must explicitly unfreeze the plan. Following upgrade, you should recompile the container code (routine, class) that contains the INSERT ... SELECT statement, or purge and re-prepare cached queries. You can then re-freeze formerly frozen plans, if desired.
Frozen Plans Interface
There are two frozen plan interfaces, used for different purposes:
Management Portal SQL Statements interface, used to freeze (or unfreeze) the plan for an individual query.
$SYSTEM.SQL.FreezePlans() method interface, used to freeze or unfreeze all plans for a namespace, a schema, a table, or an individual query.
In the Management Portal SQL interface select the Execute Query tab. Write a query, then click the Show Plan button to display the current query execution plan. If the plan is frozen, the first line in the Query Plan section is “Frozen Plan”.
In the Management Portal SQL interface select the SQL Statements tab. This displays a list of SQL Statements. The Plan State column of this list specifies Unfrozen, Unfrozen/Parallel, Frozen/Explicit, or Frozen/Upgrade. (The Plan State column is blank if the statement has no associated Query Plan.)
You can list the plan state for all SQL Statements in the current namespace using the INFORMATION.SCHEMA.STATEMENTS Frozen property values: Unfrozen (0), Frozen/Explicit (1), Frozen/Upgrade (2), or Unfrozen/Parallel (3).
To freeze or unfreeze a plan, choose an SQL statement in the SQL Statement Text column. This displays the SQL Statement Details box. At the bottom of this box it displays the Statement Text and Query Plan. The background color for these sections is green if the plan is not frozen, and blue if the plan is frozen. Just above that, under Statement Actions, you can select the Freeze Plan or Un-Freeze Plan button, as appropriate. You then select Close.
Freeze Plan button: Clicking this button will cause the query optimization plan for this statement to be frozen. When a plan is frozen, and that SQL statement is compiled, the SQL compilation will use the frozen plan information and skip the query optimization phase.
Un-Freeze Plan button: Clicking this button will delete the frozen plan for this statement and new compilations of this statement will go through query optimization phase to determine the best plan to use.
You can also freeze or unfreeze one or more plans using the FreezePlans() method. You can specify the scope of the freeze or unfreeze operation by specifying the namespace, the SQL schema name, the SQL schema.table name, or the query plan statement specified by the SQL Statement hash value.
The meaning and use of the other fields in the SQL Statement Details box are described in the “SQL Statements” chapter of this guide.
A user can view only those SQL Statements for which they have execute privileges. This applies both to Management Portal SQL Statements listings and to INFORMATION.SCHEMA.STATEMENTS class queries.
Management Portal SQL Statements access requires “USE” privilege on the %Development resource. Any user that can see an SQL Statement in the Management Portal can freeze or unfreeze it.
For catalog access to SQL Statements, you can see the statements if you are privileged to execute the statement or you have “USE” privilege on the %Development resource.
For the $SYSTEM.SQL.FreezePlan() method call, you must have “U” privilege on the %Developer resource.
Frozen Plan Different
If a plan is frozen, you can determine if unfreezing the plan would result in a different plan without actually unfreezing the plan. This information can assist you in determining which SQL statements are worth testing using %NOFPLAN to determine if unfreezing the plan would result in better performance.
You can list all frozen plans of this type in the current namespace using the INFORMATION.SCHEMA.STATEMENTS FrozenDifferent property.
A frozen plan may be different from the current query plan due to any of the following operations:
Recompiling the table or a table referenced by the table
Using SetMapSelectability() to activate or deactivate an index
Recompiling automatically purges existing cached queries. For other operations, you must manually purge existing cached queries for a new query plan to take effect.
These operations may or may not result in a different query plan. There are two ways to determine if they do:
Manually checking individual frozen plans
Automatically scanning all frozen plans on a daily basis
If the plan has not yet been checked by either of these operations, or a plan is not frozen, the SQL Statements listing New Plan column is blank. Unfreezing a checked frozen plan resets the New Plan column to blank.
Manual Frozen Plan Check
At the top of the SQL Statement Details page for a frozen plan there is a Check frozen button. Pressing this button displays the Unfrozen plan different check box. If this box is checked, unfreezing the plan would result in a different query plan.
When you have performed this Check frozen test on a frozen plan:
If the Unfrozen plan different box is checked, the SQL Statements listing New Plan column contains a “1”. This indicates that unfreezing the plan would result in a different plan.
If the Unfrozen plan different box is not checked, the SQL Statements listing New Plan column contains a “0”. This indicates that unfreezing the plan would not result in a different plan.
After performing this test, the Check frozen button disappears. If you wish to re-test a frozen plan, select the Refresh Page button. This re-displays the Check frozen button.
Automatic Daily Frozen Plan Check
Caché SQL automatically scans all frozen statements in the SQL Statement listing every night at 2:00am. This scan lasts for, at most, one hour. If the scan is not completed in one hour, Caché notes where it left off, and continues from that point on the next daily scan. You can use the Management Portal to monitor this daily scan or to force it to scan immediately: select System Operation, Task Manager, Task Schedule, then select the Scan frozen plans task.
This scan examines all frozen plans:
If the frozen plan has the same Caché version as the current version, Caché compute a hash on referenced tables and timestamps of the two plans to create an internal list of plans that may have changed. For this subset it then performs a string-for-string comparison of the two plans to determine which plans actually differ. If there is any difference between the two plans (however minor), it flags the SQL statement in the SQL Statements listing New Plan column with a “1”. This indicates that unfreezing the plan would result in a different query plan.
If the frozen plan has the same Caché version as the current version and string-for-string comparison of the two plans is an exact match, it flags the SQL statement in the SQL Statements listing New Plan column with a “0”. This indicates that unfreezing the plan would not result in a different query plan.
If the frozen plan has a different Caché version from the current version (Frozen/Update), Caché determines if a change to the SQL optimizer logic would result in a different query plan. If so, it flags the SQL statement in the SQL Statements listing New Plan column with a “1”. Otherwise, it flags the SQL statement New Plan column with a “0”.
You can check the results of this scan by invoking INFORMATION.SCHEMA.STATEMENTS. The following example returns the SQL Statements for all frozen plans, indicating whether the frozen plan is different from what the plan would be if not frozen. Note that an unfrozen statement may be Frozen=0 or Frozen=3:
SELECT Frozen,FrozenDifferent,Timestamp,Statement FROM INFORMATION_SCHEMA.STATEMENTS WHERE Frozen=1 OR Frozen=2
Frozen Plan in Error
If a statement's plan is frozen, and something changes to a definition used by the plan to cause the plan to be invalid, an error occurs. For example, if an index was deleted from the class that was used by the statement plan:
The statement's plan remains frozen.
On the SQL Statement Details page the Compile Settings area displays a Plan Error field. For example, if a query plan used an index name indxdob and then you modified the class definition to drop index indxdob, a message such as the following displays: Map 'indxdob' not defined in table 'Sample.Mytable', but it was specified in the frozen plan for the query.
On the SQL Statement Details page the Query Plan area displays Plan could not be determined due to an error in the frozen plan.
If the query is [re]compiled and the frozen plan is in an error state, Caché does not use the frozen plan. Instead, the system creates a new Query Plan that will work given the current definitions. However, this Query Plan is not preserved in a cached query or an SQL Statement if a frozen plan is in effect.
The plan in error remains in error until either the plan is unfrozen, or the definitions are modified to bring the plan back to a valid state.
If you modify the definitions to bring the plan back to a valid state, go to the SQL Statement Details page and press the Clear Error button to determine if you have corrected the error. If corrected, the Plan Error field disappears; otherwise the Plan Error message re-displays. If you have corrected the definition, you do not have to explicitly clear the plan error for Caché to begin using the frozen plan. If you have corrected the definition, the Clear Error button causes the SQL Statement Details page Frozen Query Plan area to again display the execution plan.
A Plan Error may be a “soft error.” This can occur when the plan uses an index, but that index is currently not selectable by the query optimizer because its selectability has been set to 0 by SetMapSelectability(). This was probably done so the index could be [re]built. When Caché encounters a soft error for a statement with a frozen plan, the query processor attempts to clear the error automatically and use the frozen plan. If the plan is still in error, the plan is again marked in error and query execution uses the best plan it can.
You can use the %NOFPLAN keyword to override a frozen plan. An SQL statement containing the %NOFPLAN keyword generates a new query plan. The frozen plan is retained but not used. This allows you to test generated plan behavior without losing the frozen plan.
The syntax of %NOFPLAN is as follows:
DECLARE <cursor name> CURSOR FOR SELECT %NOFPLAN ... SELECT %NOFPLAN .... INSERT [OR UPDATE] %NOFPLAN ... DELETE %NOFPLAN ... UPDATE %NOFPLAN
In a SELECT statement the %NOFPLAN keyword can only be used immediately after the first SELECT in the query: it can only be used with the first leg of a UNION query, and cannot be used in a subquery. The %NOFPLAN keyword must immediately follow the SELECT keyword, preceding other keywords such as DISTINCT or TOP.
Exporting and Importing Frozen Plans
You can export or import SQL Statements as an XML-formatted text file. This enables you to move a frozen plan from one location to another. SQL Statement exports and imports include an encoded version of the associated query plan and a flag indicating whether the plan is frozen.
To export an SQL Statement to a file, use the ExportSQLStatement() method.
To export all of the SQL Statement entries in this namespace to a file, use the ExportAllSQLStatements() method.
To import an SQL Statement or multiple SQL Statements from a file, use the ImportSQLStatement() method.