... |
* Presence of federated optimizations, such as dependent joins. |
* Ensure hints have the desired affects - see [Hints and Options], hints in the [From Clause], [Subquery Optimization], and source hints below. [Federated Optimizations]. |
All of the above information can be determined from the processing plan. You will typically be interested in analyzing the textual form of the final processing plan. To understand why particular decisions are made for debugging or support you will want to obtain the full debug log which will contain the intermediate planning steps as well as annotations as to why specific pushdown decisions are made. |
... |
XML document model queries and proecedure execution (including instead of triggers) use intermediate and final plan forms that include relational plans. Generally the structure of the xml/procedure plans will closely match their logical forms. It's the nested relational plans that will be of interest when analyzing performance issues. |
h1. Source Hints Teiid user and transformation queries can contain a meta source hint that can provide additional information to source queries. The source hint has the form: {code:sql}/*+ sh[[ KEEP ALIASES]:'arg'] source-name[ KEEP ALIASES]:'arg1' ... */{code} - The source hint is expected to appear after the query (SELECT, INSERT, UPDATE, DELETE) keyword. - Source hints may appear in any subquery or in views. All hints applicable to a given source query will be collected and pushed down together as a list. The order of the hints is not guaranteed. - The sh arg is optional and is passed to all source queries via the {{ExecutionContext.getGeneralHints}} method. The additional args should have a source-name that matches the source name assigned to the translator in the VDB. If the source-name matches, the hint values will be supplied via the {{ExecutionContext.getSourceHints}} method. See the [Developer's Guide] for more on using an ExecutionContext. - Each of the arg values has the form of a string literal - it must be surrounded in single quotes and a single quote can be escaped with another single quote. Only the Oracle translator does anything with source hints by default. The Oracle translator will use both the source hint and the general hint (in that order) if available to form an Oracle hint enclosed in /*\+ ... \*/. - If the KEEP ALIASES option is used either for the general hint or on the applicable source specific hint, then the table/view aliases from the user query and any nested views will be preserved in the push-down query. This is useful in situations where the source hint may need to reference aliases and the user does not wish to rely on the generated aliases (which can be seen in the query plan in the relevant source queries - see above). However in some situations this may result in an invalid source query if the preserved alias names are not valid for the source or result in a name collision. If the usage of KEEP ALIASES results in an error, the query could be modified by preventing view removal with the NO_UNNEST hint, the aliases modified, or the KEEP ALIASES option could be removed and the query plan used to determine the generated alias names. {code:SQL|title=Sample Source Hints}SELECT /*+ sh:'general hint' */ ... SELECT /*+ sh KEEP ALIASES:'general hint' my-oracle:'oracle hint' */ ... {code} |
h1. Debug Plans |
... |
{code} |
Here the Source corresponds to the FROM clause, the Select correspondes to the WHERE clause, the Group corresponds to the implied grouping to create the max aggregate, and the Project corresponds to the SELECT clause. |
|
Note that the affect of grouping generates what is effectively an inline view, anon_grp0, to handle the projection of values created by the gropuing. grouping. |
h2. Node Properties |
... |
** NO_UNNEST - if the no_unnest hint is set ** MAKE_IND - if the make ind hint is set |
** SOURCE_HINT - the source hint. See Source Hints above. [Federated Optimizations]. |
** ACCESS_PATTERNS - access patterns yet to be satisfied ** ACCESS_PATTERN_USED - satisfied access patterns |
... |
* Choose Dependent - choose dependent joins based upon the cost/hints * Choose Join Strategy - choose the join strategy base upon the cost |
* Clean Criteria - removes phantom criteria and combines other select nodes |
* Collapse Source - takes all of the nodes below an access node and creates a SQL query representation * Copy Criteria - copies criteria based upon join predicates |
* Decompose Join - optimizes joins over partitioned unions |
* Implement Join Strategy - adds necessary sort and other nodes to process the chosen join strategy |
* Merge Criteria - combines select nodes and can convert subqueries to semi-joins |
* Merge Virtual - removes view and inline view layers |
* Place Access - places access nodes under source nodes |
* Plan Joins - determines the best join order |
* Plan Procedures - plans procedures that appear in procedural relational queries |
* Plan Sorts - optimizations around sorting, such as combining sort operations or moving projection |
* Plan Unions - reorders union children for more pushdown |
* Plan Aggregates - performs aggregate decomposition over a join or union |
* Push Limit - pushes the affect of a limit node further into the plan |
* Push Non-Join Criteria - pushes non-equi join conditions out of the on clause when possible |
* Push Select Criteria - pushed select nodes as far as possible |
* Raise Access - raises access nodes, which increases the work done by source queries |
* Raise Null - raises null nodes |
* Remove Optional Joins - removes joins that are marked as or determined to be optional |
* Substitute Expressions - used only when a function based index is present |
* Validate Where All - ensures criteria is used when required by the source |
... |
When integrating information using a federated query planner it is useful to view the query plans to better understand how information is being accessed and processed, and to troubleshoot problems.
A query plan is a set of instructions created by a query engine for executing a command submitted by a user or application. The purpose of the query plan is to execute the user's query in as efficient a way as possible.
You can get a query plan any time you execute a command. The SQL options available are as follows:
SET SHOWPLAN [ON|DEBUG]- Returns the processing plan or the plan and the full planner debug log. See also the SET Statement.
With the above options, the query plan is available from the Statement object by casting to the org.teiid.jdbc.TeiidStatement interface or by using the "SHOW PLAN" statement.
statement.execute("set showplan on"); ResultSet rs = statement.executeQuery("select ..."); TeiidStatement tstatement = statement.unwrap(TeiidStatement.class); PlanNode queryPlan = tstatement.getPlanDescription(); System.out.println(queryPlan);
The query plan is made available automatically in several of Teiid's tools.
Once a query plan has been obtained you will most commonly be looking for:
All of the above information can be determined from the processing plan. You will typically be interested in analyzing the textual form of the final processing plan. To understand why particular decisions are made for debugging or support you will want to obtain the full debug log which will contain the intermediate planning steps as well as annotations as to why specific pushdown decisions are made.
A query plan consists of a set of nodes organized in a tree structure. If you are executing a procedure or generating an XML document from an XML Document Model, the overall query plan will contain additional information related the surrounding procedural execution.
In a procedural context the ordering of child nodes implies the order of execution. In most other situation, child nodes may be executed in any order even in parallel. Only in specific optimizations, such as dependent join, will the children of a join execute serially.
Relational plans represent the processing plan that is composed of nodes representing building blocks of logical relational operations. Relational processing plans differ from logical debug relational plans in that they will contain additional operations and execution specifics that were chosen by the optimizer.
The nodes for a relational query plan are:
Every node has a set of statistics that are output. These can be used to determine the amount of data flowing through the node.
Statistic | Description | Units |
---|---|---|
Node Output Rows | Number of records output from the node | count |
Node Process Time | Time processing in this node only | millisec |
Node Cumulative Process Time | Elapsed time from beginning of processing to end | millisec |
Node Cumulative Next Batch Process Time | Time processing in this node + child nodes | millisec |
Node Next Batch Calls | Number of times a node was called for processing | count |
Node Blocks | Number of times a blocked exception was thrown by this node or a child | count |
In addition to node statistics, some nodes display cost estimates computed at the node.
Cost Estimates | Description | Units |
---|---|---|
Estimated Node Cardinality | Estimated number of records that will be output from the node; -1 if unknown | count |
The root node will display additional information.
Top level Statistics | Description | Units |
---|---|---|
Data Bytes Sent | The size of the serialized data result (row and lob values) sent to the client | bytes |
XML document model queries and proecedure execution (including instead of triggers) use intermediate and final plan forms that include relational plans. Generally the structure of the xml/procedure plans will closely match their logical forms. It's the nested relational plans that will be of interest when analyzing performance issues.
A relational processing plan is created by the optimizer after the logical plan is manipulated by a series of rules. The application of rules is determined both by the query structure and by the rules themselves. The node structure of the debug plan resembles that of the processing plan, but the node types more logically represent SQL operations.
User SQL statements after rewrite are converted into a cannonical plan form. The connonical plan form most closely resembles the initial SQL structure. For example, a SQL statement such as SELECT max(pm1.g1.e1) FROM pm1.g1 WHERE e2 = 1 creates a logical plan:
Project(groups=[anon_grp0], props={PROJECT_COLS=[anon_grp0.agg0 AS expr1]}) Group(groups=[anon_grp0], props={SYMBOL_MAP={anon_grp0.agg0=MAX(pm1.g1.e1)}}) Select(groups=[pm1.g1], props={SELECT_CRITERIA=e2 = 1}) Source(groups=[pm1.g1])
Here the Source corresponds to the FROM clause, the Select corresponds to the WHERE clause, the Group corresponds to the implied grouping to create the max aggregate, and the Project corresponds to the SELECT clause.
Note that the affect of grouping generates what is effectively an inline view, anon_grp0, to handle the projection of values created by the grouping.
Each node has a set of applicable properties that are typically shown on the node.
Plan rule manipulate the plan tree, fire other rules, and drive the optimization process. The structure of the query determines the initial set of rules. Each rule is designed to perform a narrow set of tasks. Some rules can be run multiple times. Some rules require a specific set of precursors to run properly.
As each relational sub plan is optimized, the plan will show what is being optimized and it's canonical form:
OPTIMIZE: SELECT e1 FROM (SELECT e1 FROM pm1.g1) AS x ---------------------------------------------------------------------------- GENERATE CANONICAL: SELECT e1 FROM (SELECT e1 FROM pm1.g1) AS x CANONICAL PLAN: Project(groups=[x], props={PROJECT_COLS=[e1]}) Source(groups=[x], props={NESTED_COMMAND=SELECT e1 FROM pm1.g1, SYMBOL_MAP={x.e1=e1}}) Project(groups=[pm1.g1], props={PROJECT_COLS=[e1]}) Source(groups=[pm1.g1])
With more complicated user queries, such as a procedure invocation or one containing subqueries, the sub plans may be nested within the overall plan. Each plan ends by showing the final processing plan:
---------------------------------------------------------------------------- OPTIMIZATION COMPLETE: PROCESSOR PLAN: AccessNode(0) output=[e1] SELECT g_0.e1 FROM pm1.g1 AS g_0
The affect of rules can be seen by the state of the plan tree before and after the rule fires. For example, the debug log below shows the application of rule merge virtual, which will remove the "x" inline view layer:
EXECUTING AssignOutputElements AFTER: Project(groups=[x], props={PROJECT_COLS=[e1], OUTPUT_COLS=[e1]}) Source(groups=[x], props={NESTED_COMMAND=SELECT e1 FROM pm1.g1, SYMBOL_MAP={x.e1=e1}, OUTPUT_COLS=[e1]}) Project(groups=[pm1.g1], props={PROJECT_COLS=[e1], OUTPUT_COLS=[e1]}) Access(groups=[pm1.g1], props={SOURCE_HINT=null, MODEL_ID=Schema name=pm1, nameInSource=null, uuid=3335, OUTPUT_COLS=[e1]}) Source(groups=[pm1.g1], props={OUTPUT_COLS=[e1]}) ============================================================================ EXECUTING MergeVirtual AFTER: Project(groups=[pm1.g1], props={PROJECT_COLS=[e1], OUTPUT_COLS=[e1]}) Access(groups=[pm1.g1], props={SOURCE_HINT=null, MODEL_ID=Schema name=pm1, nameInSource=null, uuid=3335, OUTPUT_COLS=[e1]}) Source(groups=[pm1.g1])
Some important planning decisions are shown in the plan as they occur as an annotation. For example the snippet below shows that the access node could not be raised as the parent select node contained an unsupported subquery.
Project(groups=[pm1.g1], props={PROJECT_COLS=[e1], OUTPUT_COLS=null}) Select(groups=[pm1.g1], props={SELECT_CRITERIA=e1 IN /*+ NO_UNNEST */ (SELECT e1 FROM pm2.g1), OUTPUT_COLS=null}) Access(groups=[pm1.g1], props={SOURCE_HINT=null, MODEL_ID=Schema name=pm1, nameInSource=null, uuid=3341, OUTPUT_COLS=null}) Source(groups=[pm1.g1], props={OUTPUT_COLS=null}) ============================================================================ EXECUTING RaiseAccess LOW Relational Planner SubqueryIn is not supported by source pm1 - e1 IN /*+ NO_UNNEST */ (SELECT e1 FROM pm2.g1) was not pushed AFTER: Project(groups=[pm1.g1]) Select(groups=[pm1.g1], props={SELECT_CRITERIA=e1 IN /*+ NO_UNNEST */ (SELECT e1 FROM pm2.g1), OUTPUT_COLS=null}) Access(groups=[pm1.g1], props={SOURCE_HINT=null, MODEL_ID=Schema name=pm1, nameInSource=null, uuid=3341, OUTPUT_COLS=null}) Source(groups=[pm1.g1])
XQuery is eligible for specific optimizations. Document projection is the most common optimization. It will be shown in the debug plan as an annotation. For example with the user query containing "xmltable('/a/b' passing doc columns x string path '@x', val string path '/.')", the debug plan would show a tree of the document that will effectively be used by the context and path XQuerys:
MEDIUM XQuery Planning Projection conditions met for /a/b - Document projection will be used childelement(Q{}a) childelement(Q{}b) attributeattribute(Q{}x) childtext() childtext()