The TimesTen cost-based query optimizer uses information about an application's tables and their available indexes to choose a fast path to the data. Application developers can examine the plan chosen by the optimizer to check that indexes are used appropriately. If necessary, application developers can also modify the optimizer's behavior so that it chooses a different plan.
This chapter includes the following topics:
It is useful to understand when TimesTen performs query optimization, since a single command may be optimized several times.
TimesTen invokes the optimizer whenever a SELECT
, UPDATE
, DELETE
, INSERT SELECT
or CREATE MATERIALIZED VIEW
statement is prepared through an ODBC SQLPrepare
or SQLExecDirect
function or any of the JDBC execute methods. The resulting plan persists until an invalidating event occurs, or the command is dropped by the application. A command is invalidated under the following circumstances:
A table it uses is dropped
A table it uses is altered
An index on a table it references is dropped
An index is created on a table it references
Statistics are recomputed with the invalidation
option set to 1 in either the ttIsql
statsupdate
command, the ttOptUpdateStats
built-in procedure, or the ttOptEstimateStats
built-in procedures.
Note:
For complete details on when to calculate statistics, see "Compute exact or estimated statistics". In addition, see "ttIsql," "ttOptUpdateStats," or "ttOptEstimateStats" in the Oracle TimesTen In-Memory Database Reference.If you choose to not invalidate the commands in the SQL command cache, you can manually initiate an invalidation of all commands with the ttOptCmdCacheInvalidate
built-in procedure. For more information, see "Control the invalidation of commands in the SQL Command Cache".
An invalid command is usually reprepared automatically just before it is re-executed. This means that the optimizer is invoked again at this time, possibly resulting in a new plan. Thus, a single command may be prepared several times.
Note:
When using JDBC, you must manually reprepare commands when a table has been altered.A command may have to be prepared manually if, for example, the table that the command referenced was dropped and a new table with the same name was created. When you prepare a statement manually, you should commit the prepare statement so it can be shared. If the command is recompiled because it was invalid, and if recompilation involves DDL on one of the referenced tables, then the prepared statement must be committed to release the command lock.
For example, in ODBC a command joining tables T1
and T2
may undergo the following changes:
Action | Description |
---|---|
SQLPrepare |
Command is prepared. |
SQLExecute |
Command is executed. |
SQLExecute |
Command is re-executed. |
Create Index on T1 | Command is invalidated. |
SQLExecute |
Command is reprepared, then executed. |
SQLExecute |
Command is re-executed. |
ttOptUpdateStats on T1 |
Command is invalidated if the invalidate flag is passed to the ttOptUpdateStats procedure. |
SQLExecute |
Command is reprepared, then executed. |
SQLExecute |
Command is re-executed. |
SQLFreeStmt |
Command is dropped. |
In JDBC, a command joining tables T1
and T2
may undergo the following changes:
Action | Description |
---|---|
Connection.prepareStatement |
Command is prepared. |
PreparedStatement.execute |
Command is executed. |
PreparedStatement.execute |
Command is re-executed. |
Create Index on T1 | Command is invalidated. |
PreparedStatement.execute |
Command is reprepared, then executed. |
PreparedStatement.execute |
Command is re-executed. |
ttOptUpdateStats on T1 |
Command is invalidated if the invalidate flag is passed to the ttOptUpdateStats procedure. |
PreparedStatement.execute |
Command is reprepared, then executed. |
PreparedStatement.execute |
Command is re-executed. |
PreparedStatement.close |
Command is dropped. |
As illustrated, optimization is generally performed at prepare time, but it may also be performed later when indexes are dropped or created, or when statistics are modified. Optimization does not occur if a prepare can use a command in the cache.
If a command was prepared with the genPlan
flag set, it will be recompiled with the same flag set. Thus, the plan is generated even though the plan for another query was found in the SYS.PLAN
table.
If an application specifies hints to modify the optimizer's behavior, these hints persist until the command is deleted. See "Modifying plan generation"" for more information. For example, when the ODBC SQLPrepare
function or JDBC Connection.prepareStatement
method is called again on the same handle or when the SQLFreeStmt
function or PreparedStatement.close
method is called. This means that any intermediate reprepare operations that occur because of invalidations will use those same hints.
All commands executed—SQL statements, built-in procedures, and so on—are stored in the SQL Command Cache, which uses temporary memory. The commands are stored up until the limit of the SQL Command Cache is reached, then the new commands are stored after the last used commands are removed. You can retrieve one or more of these commands that are stored in the SQL Command Cache.
Note:
This section describes viewing the commands stored in the SQL Command Cache. For details on how to view the query plans associated with these commands, see "Viewing query plans associated with commands stored in the SQL Command Cache".The following sections describe how to view commands cached in the SQL Command Cache:
You can view all one or more of the SQL commands or details of their query plans with the ttSqlCmdCacheInfo
and ttSqlCmdQueryPlan
built-in procedures. Use the query plan information to monitor and troubleshoot your queries.
Viewing the SQL commands and query plans can help you perform the following:
Detect updates or deletes that are not using an index scan.
Monitor query plans of executing queries to ensure all plans are optimized.
Detect applications that do not prepare SQL statements or that re-prepare the same statement multiple times.
Discover the percentage of space used in the command cache for performance evaluation.
The commands executed against the TimesTen database are cached in the SQL command cache. The ttSqlCmdCacheInfo
built-in procedure displays a specific or all cached commands in the TimesTen SQL command cache. By default, all commands are displayed; if you specify a command id, then only this command is retrieved for display.
The command data is saved in the following format:
Command identifier, which is used to retrieve a specific command or its associated query plan.
Private connection identifier.
Counter for the number of executions.
Counter for the number of times the user prepares this statement.
Counter for the number of times the user re-prepares this statement.
Freeable status, where if the value is one, then the subdaemon can free the space with the garbage collector. A value of zero determines that the space is not able to be freed.
Total size in bytes allocated for this command in the cache.
User who created the command.
Query text up to 1024 characters.
At the end of the list of all SQL commands, a status is printed of how many commands were in the cache.
The following examples show how to display all or a single SQL command from the SQL Command Cache using the ttSqlCmdCacheInfo
built-in utility:
Example 10-1 Displaying all SQL commands in the SQL Command Cache
This example executes within ttIsql
the ttSqlCmdCacheInfo
built-in procedure without arguments to show all cached SQL commands. The SQL commands are displayed in terse format. To display the information where each column is prepended with the column name, execute vertical on
before executing the ttsqlCmdCacheInfo
procedure.
Command> call ttsqlCmdCacheInfo; < 528079360, 2048, 0, 1, 0, 1, 2168, PAT , select * from t7 where x7 is not null or exists (select 1 from t2,t3 where not 'tuf' like 'abc') > < 527609108, 2048, 0, 1, 0, 1, 2960, PAT , select * from t1 where x1 = (select x2 from t2 where z2 in (1,3) and y1=y2) order by 1, 2, 3 > < 528054656, 2048, 0, 1, 0, 1, 1216, PAT , create table t2(x2 int,y2 int, z2 int) > < 528066648, 2048, 0, 1, 0, 1, 1176, PAT , insert into t2 select * from t1 > < 528013192, 2048, 0, 1, 0, 1, 1848, PAT , select * from t1 where exists (select * from t2 where x1=x2) or y1=1 > < 527582620, 2048, 0, 1, 0, 1, 1240, PAT , insert into t2 select * from t1 > < 527614292, 2048, 0, 1, 0, 1, 2248, PAT , select * from t1 where exists (select x2 from t2 where x1=x2) order by 1, 2, 3 > < 528061248, 2048, 0, 1, 0, 1, 696, PAT , create index i1 on t3(y3) > < 528070368, 2048, 0, 1, 0, 1, 824, PAT , call ttOptSetOrder('t3 t4 t2 t1') > < 528018856, 2048, 0, 1, 0, 1, 984, PAT , insert into t2 select * from t1 > < 527606460, 2048, 0, 1, 0, 1, 2624, PAT , select * from t1 where x1 = (select x2 from t2 where y1=y2) order by 1, 2, 3 > < 528123000, 2048, 0, 1, 0, 1, 3616, PAT , select * from t1 where x1 = 1 or x1 = (select x2 from t2,t3 where z2=t3.x3) > < 528074624, 2048, 0, 1, 0, 1, 856, PAT , call ttOptSetOrder('t4 t2 t3 t1') > < 527973892, 2048, 0, 1, 0, 1, 2872, PAT , select * from t1 where x1 in (select x2 from t2) or x1 in (select x3 from t3) order by 1, 2, 3 > < 527953876, 2048, 0, 1, 0, 1, 3000, PAT , select * from t1 where x1 = (select x2 from t2) order by 1, 2, 3 > < 527603900, 2048, 0, 1, 0, 1, 2440, PAT , select * from t1 where x1 in (select x2 from t2 where y1=y2) order by 1, 2, 3 > < 528093308, 2048, 0, 1, 0, 1, 3608, PAT , select * from t1 where x1 = 1 or x1 = (select x2 from t2,t3 where z2=t3.x3 and t3.z3=1) > < 528060608, 2048, 0, 1, 0, 1, 696, PAT , create index i1 on t2 (y2) >
Example 10-2 Displaying a single SQL command
If you provide a command id as the input for the ttSqlCmdCacheInfo
, the single SQL command is displayed from within the SQL Command Cache. You can discover the command id from executing this built-in without input. The command id is the first column displayed.
The following example displays the SQL command identified by Command ID of 527973892. It is displayed in terse format; to view with the column headings prepended, execute vertical on
before executing the ttSqlCmdCacheInfo
built-in.
Command> call ttsqlCmdCacheInfo(527973892); < 527973892, 2048, 0, 1, 0, 1, 2872, PAT , select * from t1 where x1 in (select x2 from t2) or x1 in (select x3 from t3) order by 1, 2, 3 > 1 row found.
You can view the query plan for a SQL command in one of two ways: storing the latest query plan into the system PLAN
table or viewing all cached SQL commands and their query plans in the SQL command cache. Both methods are described in the following sections:
The optimizer prepares the query plans. For the last SQL command to be executed—such as a prepared SELECT
, UPDATE
, DELETE
, INSERT
SELECT
, CREATE TABLE
, CREATE MATERIALIZED VIEW
and so on—you can instruct that the plan be stored in the system PLAN table:
Instruct TimesTen to generate the plan and store it in the system PLAN table.
Prepare the statement means calling the ODBC S
QLPrepare
function or JDBC Connection.prepareStatement
method on the statement. TimesTen stores the plan into the PLAN
table.
Read the generated plan within the SYS.PLAN
table.
The stored plan is updated automatically whenever the command is reprepared. Re-preparation occurs automatically if one ore more of the following occurs:
A table in the statement is altered.
If indexes are created or dropped.
The application invalidates commands when statistics are updated with the invalidate
option in the ttOptUpdateStats
built-in procedure.
The user invalidates commands with the ttOptCmdCacheInvalidate
built-in procedure.
Note:
For more information, see "Control the invalidation of commands in the SQL Command Cache". For more information on the built-in procedures, seettOptUpdateStats
and ttOptCmdCacheInvalidate
in the Oracle TimesTen In-Memory Database Reference.For these cases, read the PLAN
table to view how the plan has been modified.
Before you can view the plan in the system PLAN
table, call the built-in ttOptSetFlag
procedure with the GenPlan
flag. This call informs TimesTen that all subsequent calls to the ODBC SQLPrepare
function or JDBC Connection.prepareStatement
method in the transaction should store the resulting plan in the current SYS.PLAN
table.
Note:
Make sureAUTOCOMMIT
is not set. If it is, the current transaction completes after the processing of the command and prepares in the next transaction are not affected.The SYS.PLAN
table only stores one plan, so each call to the ODBC SQLPrepare
function or JDBC Connection.prepareStatement
method overwrites any plan currently stored in the table.
If a command is prepared with the genPlan
flag set, it is recompiled with this flag. Thus, the plan is generated even though the plan for another query was found in the SYS.PLAN
table.
For example, try the query and optimizer hints with the ttIsql
utility. To display optimizer plans, issue the following commands:
autocommit 0; showplan 1;
Once plan generation has been turned on and a command has been prepared, one or more rows in the SYS.PLAN
table store the plan for the command. The number of rows in the table depends on the complexity of the command. Each row has seven columns, as described in "System Tables" in the Oracle TimesTen In-Memory Database System Tables and Limits Reference.
Example 10-3 Generating a query plan
This example uses the following query:
SELECT COUNT(*) FROM T1, T2, T3 WHERE T3.B/T1.B > 1 AND T2.B <> 0 AND T1.A = -T2.A AND T2.A = T3.A
The optimizer generates the five SYS.PLAN
rows shown in the following table. Each row is one step in the plan and reflects an operation that is performed during query execution.
Step | Level | Operation | TblNames | IXName | Pred | Other Pred |
---|---|---|---|---|---|---|
1 | 3 | TblLkTtreeScan | T1 | IX1 | ||
2 | 3 | TblLkTtreeScan | T2 | IX2(D) | T2.B <> 0 | |
3 | 2 | MergeJoin | T1.A = -T2.A | |||
4 | 2 | TblLkTtreeScan | T3 | IX3(D) | ||
5 | 1 | MergeJoin | T2.A = T3.A | T3.B / T1.B > 1 |
For details about each column in the SYS.PLAN
table, see "Describing the PLAN table columns".
The SYS.PLAN
table has seven columns.
Indicates the order of operation, which always starts with one. Example 10-3 uses a table lock range scan in the following order:
Table locking range scan of IX1 on table T1
.
Table locking range scan of IX2 on T2
.
Merge join of T1
and T2
and so forth.
Indicates the position of the operation in the join-tree diagram that describes the execution. For Example 10-3, the join tree is as follows:
Indicates the type of operation being executed. For a description of the potential values in this field and the type of table scan each represents, see SYS.PLAN in "System Tables" in the Oracle TimesTen In-Memory Database System Tables and Limits Reference.
Not all operations the optimizer performs are visible to the user. Only operations significant to performance analysis are shown in the SYS.PLAN
table. TblLk is an optimizer hint that is honored at execution time in Serializable or Read Committed isolation. Table locks are used during a scan only if row locks are disabled during preparation.
Indicates the table that is being scanned. This column is used only when the operation is a scan. In all other cases, this column is NULL
.
Indicates the index that is being used. This column is used only when the operation is an index scan using an existing index—such as a hash or range scan. In all other cases, this column is NULL
. Names of range indexes are followed with "(D)" if the scan is descending—from large to small rather than from small to large.
Indicates the predicate that participates in the operation, if there is one. Predicates are used only with index scan and MergeJoin
operations. The predicate character string is limited to 1,024 characters.
This column may be NULL
—indicating no predicate—for a range scan. The optimizer may choose a range scan over a table scan because, in addition to filtering, it has two useful properties:
Rows are returned in sorted order, on index key.
Rows may be returned faster, especially if the table is sparse.
In Example 10-3, the range scans are used for their sorting capability; none of them evaluates a predicate.
Indicates any other predicate that is applied while the operation is being executed. These predicates do not participate directly in the scan or join but are evaluated on each row returned by the scan or join.
For example, at step two of the plan generated for Example 10-3, a range scan is performed on table T2
. When that scan is performed, the predicate T2.B <> 0
is also evaluated. Similarly, once the final merge-join has been performed, it is then possible to evaluate the predicate T3.B / T1.B > 1
.
Use the query plan information to monitor and troubleshoot your queries.
Note:
For more reasons why to use thettSqlCmdQueryPlan
built-in procedure, see "Managing performance and troubleshooting commands".The ttSqlCmdQueryPlan
built-in procedure displays the query plan of a specific statement or all statements in the command cache. It displays the detailed run-time query plans for the cached SQL queries. By default, all query plans are displayed; if you specify the command id taken from the SQL command output, only the query plan for the specified SQL command is displayed.
Note:
If you want to display a query plan for a specific command, you must provide the command identifier, which is displayed with thettSqlCmdCacheInfo
built-in procedure. See "Displaying commands stored in the SQL Command Cache" for full details.The plan data displayed when you invoke this built-in procedure is as follows:
Command identifier
Query text up to 1024 characters
Step number of the current operation in the run-time query plan
Level number of the current operation in the query plan tree
Operation name of current step
Name of table used
Owner of the table
Name of index used
If used and available, the index predicate
If used and available, the non-indexed predicate
Note:
For more information on how to view this information, see "Reading query plan from the PLAN table". The source of the data may be different, but the mapping and understanding of the material is the same as the query plan in the systemPLAN
table.The ttSqlCmdQueryPlan
built-in process displays the query plan in a raw data format. Alternatively, you can execute the ttIsql
explain
command for a formatted version of this output. For more information, see "Display query plan for statement in SQL Command Cache".
The following examples show how to display all or a single SQL query plan from the SQL Command Cache using the ttSqlCmdQueryPlan
built-in procedure:
Example 10-4 Displaying all SQL query plans
You can display all SQL query plans associated with commands stored in the command cache with the ttSqlCmdQuery
plan built-in procedure within the ttIsql
utility.
The following example shows the output when executing the ttSqlCmdQueryPlan
built-in procedure without arguments, which displays detailed run-time query plans for all valid queries. For invalid queries, there is no query plan; instead, the query text is displayed.
The query plans are displayed in terse format; to view with the column headings prepended, execute vertical on
before executing the ttSqlCmdQueryPlan
built-in procedure.
Note: For complex expressions, there may be some difficulties in printing out the original expressions.
Command> call ttSqlCmdQueryPlan(); < 528079360, select * from t7 where x7 is not null or exists (select 1 from t2,t3 where not 'tuf' like 'abc'), <NULL>, <NULL>, <NULL>, <NULL>, <NULL>, <NULL>, <NULL>, <NULL> > < 528079360, <NULL>, 0, 2, RowLkSerialScan , T7 , PAT , , , > < 528079360, <NULL>, 1, 3, RowLkTtreeScan , T2 , PAT , I2 , , NOT(LIKE( tuf ,abc ,NULL )) > < 528079360, <NULL>, 2, 3, RowLkTtreeScan , T3 , PAT , I2 , , > < 528079360, <NULL>, 3, 2, NestedLoop , , , , , > < 528079360, <NULL>, 4, 1, NestedLoop(Left OuterJoin) , , , , , > < 528079360, <NULL>, 5, 0, Filter , , , , , X7 > < 527576540, call ttSqlCmdQueryPlan(527973892), <NULL>, <NULL>, <NULL>, <NULL>, <NULL>, <NULL>, <NULL>, <NULL> > < 527576540, <NULL>, 0, 0, Procedure Call , , , , , > < 528054656, create table t2(x2 int,y2 int, z2 int), <NULL>, <NULL>, <NULL>, <NULL>, <NULL>, <NULL>, <NULL>, <NULL> > < 528066648, insert into t2 select * from t1, <NULL>, <NULL>, <NULL>, <NULL>, <NULL>, <NULL>, <NULL>, <NULL> > < 528066648, <NULL>, 0, 0, Insert , T2 , PAT , , , > < 528013192, select * from t1 where exists (select * from t2 where x1=x2) or y1=1, <NULL>, <NULL>, <NULL>, <NULL>, <NULL>, <NULL>, <NULL>, <NULL> > < 528061248, create index i1 on t3(y3), <NULL>, <NULL>, <NULL>, <NULL>, <NULL>, <NULL>, <NULL>, <NULL> > < 528070368, call ttOptSetOrder('t3 t4 t2 t1'), <NULL>, <NULL>, <NULL>, <NULL>, <NULL>, <NULL>, <NULL>, <NULL> > < 528070368, <NULL>, 0, 0, Procedure Call , , , , , > < 528018856, insert into t2 select * from t1, <NULL>, <NULL>, <NULL>, <NULL>, <NULL>, <NULL>, <NULL>, <NULL> > < 527573452, call ttsqlCmdCacheInfo(527973892), <NULL>, <NULL>, <NULL>, <NULL>, <NULL>, <NULL>, <NULL>, <NULL> > < 527573452, <NULL>, 0, 0, Procedure Call , , , , , > < 528123000, select * from t1 where x1 = 1 or x1 = (select x2 from t2,t3 where z2=t3.x3), <NULL>, <NULL>, <NULL>, <NULL>, <NULL>, <NULL>, <NULL>, <NULL> > < 528123000, <NULL>, 0, 2, RowLkSerialScan , T1 , PAT , , , > < 528123000, <NULL>, 1, 6, RowLkTtreeScan , T2 , PAT , I2 , , > < 528123000, <NULL>, 2, 6, RowLkTtreeScan , T3 , PAT , I2 , , Z2 = X3; > < 528123000, <NULL>, 3, 5, NestedLoop , , , , , > < 528123000, <NULL>, 4, 4, Materialized View , , , , , > < 528123000, <NULL>, 5, 3, GroupBy , , , , , > < 528123000, <NULL>, 6, 2, Filter , , , , , X1 = colum_name; > < 528123000, <NULL>, 7, 1, NestedLoop(Left OuterJoin) , , , , , > < 528123000, <NULL>, 8, 0, Filter , , , , , X1 = 1; >
Example 10-5 Displaying a single SQL query plan
You can display any query plan associated with a SQL command by providing the command id of the SQL command as the input for the ttSqlCmdQueryPlan
built-in procedure. The single query plan is displayed from within the SQL Command Cache. You can discover the command id from executing this ttSqlCmdCacheInfo
built-in without input. The command id is the first column displayed.
The following example displays the query plan of the SQL command identified by command id of 528078576. It is displayed in terse format; to view with the column headings prepended, execute vertical on
before executing the ttSqlCmdQueryPlan
built-in procedure.
Note: for complex expressions, there are some difficulties to print original expressions.
Command> call ttSqlCmdQueryPlan( 528078576); < 528078576, select * from t1 where 1=2 or (x1 in (select x2 from t2, t5 where y2 in (select y3 from t3)) and y1 in (select x4 from t4)), <NULL>, <NULL>, <NULL>, <NULL>, <NULL>, <NULL>, <NULL>, <NULL> > < 528078576, <NULL>, 0, 4, RowLkSerialScan , T1 , PAT , , , > < 528078576, <NULL>, 1, 7, RowLkTtreeScan , T2 , PAT , I2 , , > < 528078576, <NULL>, 2, 7, RowLkTtreeScan , T5 , PAT , I2 , , > < 528078576, <NULL>, 3, 6, NestedLoop , , , , , > < 528078576, <NULL>, 4, 6, RowLkTtreeScan , T3 , PAT , I1 , ( (Y3=Y2; ) ) , > < 528078576, <NULL>, 5, 5, NestedLoop , , , , , > < 528078576, <NULL>, 6, 4, Filter , , , , , X1 = X2; > < 528078576, <NULL>, 7, 3, NestedLoop(Left OuterJoin) , , , , , > < 528078576, <NULL>, 8, 2, Filter , , , , , > < 528078576, <NULL>, 9, 2, RowLkTtreeScan , T4 , PAT , I2 , , Y1 = X4; > < 528078576, <NULL>, 10, 1, NestedLoop(Left OuterJoin) , , , , , > < 528078576, <NULL>, 11, 0, Filter , , , , , > 13 rows found. Command>
If you decide that you want to modify a query plan, you can only modify the query plan that exists in the system PLAN
table, as described in "Viewing a query plan from the system PLAN table". Once you do modify the query plan, it does not replace the query plan, but creates a new query plan with your changes.
The following sections describe why you may want to modify execution plans and then how to modify them:
Applications may want to modify an execution plan for two reasons:
The plan is optimally fast but is ill-suited for the application. The optimizer may select the fastest execution path, but this path may not be desirable from the application's point of view. For example, if the optimizer chooses to use certain indexes, these choices may prevent other operations-such as certain update or delete operations-from occurring simultaneously on the indexed tables. In this case, an application can prevent the use of those indexes.
The plan chosen by the optimizer may also consume more memory than is available or than the application wants to allocate. For example, this may happen if the plan stores intermediate results or requires the creation of temporary indexes.
The plan is not optimally performant. The query optimizer chooses the plan that it estimates will execute the fastest based on its knowledge of the tables' contents, available indexes, statistics and the relative costs of various internal operations. The optimizer often has to make estimates or generalizations when evaluating this information, so there can be instances where it does not choose the fastest plan. In this case, an application can adjust the optimizer's behavior to try to produce a better plan.
Applications can modify an execution plan by providing hints to the optimizer. Hints are specified by calls to one of the TimesTen optimizer built-in procedures and are in effect for all calls to the ODBC SQLPrepare
function or JDBC PreparedStatement objects in the transaction. For more information on how to provide these hints, see "How to modify execution plan generation".
Note:
Make sureAUTOCOMMIT
is not set. If it is, the current transaction completes after processing the ttOptSetFlag
procedure and prepares in the next transaction are not affected.If a command is prepared with certain hints in effect, those hints continue to apply if the command is reprepared automatically, even when this happens outside the initial prepare transaction. This can happen when a table is altered, or an index is dropped or created, or when statistics are modified, as described in "When optimization occurs".
If a command is prepared without hints, subsequent hints will not affect the command if it is reprepared automatically. An application must call the ODBC SQLPrepare
function or JDBC Connection.prepareStatement
method a second time so that hints have an effect.
Example 10-6 Tuning a join when using ODBC
When using ODBC, a developer tuning a join on T1
and T2
might go through the steps shown in the following figure.
During execution, the application may then go through the steps shown in the following figure.
Example 10-7 Tuning a join when using JDBC
When using JDBC, a developer tuning a join on T1
and T2
might go through the steps shown in the following figure.
During execution, the application may then go through the steps shown in the following figure.
To change the query optimizer behavior, an application calls one of the following built-in procedures using the ODBC procedure call interface:
ttOptSetFlag
—Sets certain optimizer parameters.
ttOptSetOrder
—Allows an application to specify the table join order.
ttOptUseIndex
—Allows an application to specify that an index be used or to disable the use of certain indexes.
ttOptClearStats
, ttOptEstimateStats
, ttOptSetColIntvlStats
, ttOptSetTblStats
, ttOptUpdateStats
—Manipulate statistics that the TimesTen Data Manager maintains on the application's data that are used by the query optimizer to estimate costs of various operations.
Some of these built-in procedures require that the user have privileges to the objects on which the utility executes. For full details on these built-in procedures and any privileges required, see "Built-In Procedures" in the Oracle TimesTen In-Memory Database Reference.
The following examples provide an ODBC and JDBC method on how to use the ttOptSetFlag
built-in procedure:
Note:
You can also experiment with optimizer settings using thettIsql
utility. The commands that start with try
control the optimizer hints. To view your current optimizer hint settings, use the optprofile
command.Example 10-8—JDBC example.
Example 10-9—ODBC example.
Example 10-8 Using ttOptSetFlag in JDBC
This JDBC example illustrates the use of ttOptSetFlag
to prevent the optimizer from choosing a merge join.
import java.sql.*; class Example { public void myMethod() { CallableStatement cStmt; PreparedStatement pStmt; . . . . . try { . . . . . . . // Prevent the optimizer from choosing Merge Join cStmt = con.prepareCall("{ CALL ttOptSetFlag('MergeJoin', 0)}"); cStmt.execute(); // Next prepared query pStmt=con.prepareStatement( "SELECT * FROM Tbl1, Tbl2 WHERE Tbl1.ssn=Tbl2.ssn"); . . . . . . . catch (SQLException ex) { ex.printStackTrace(); } } . . . . . . . }
Example 10-9 Using ttOptSetFlag in ODBC
This ODBC example illustrates the use of ttOptSetFlag
to prevent the optimizer from choosing a merge join.
#include <sql.h> SQLRETURN rc; SQLHSTMT hstmt; fetchStmt; .... rc = SQLExecDirect (hstmt, (SQLCHAR *) "{CALL ttOptSetFlag (MergeJoin, 0)}", SQL_NTS) /* check return value */ ... rc = SQLPrepare (fetchStmt, ...) /* check return value */ ...