An abstract plan describes the execution plan for a query using a language created for that purpose. This language contains operators to specify the choices and actions that can be generated by the optimizer.
Adaptive Server can generate an abstract plan for a query, and save the text and its associated abstract plan in the sysqueryplans system table. Using a rapid hashing method, incoming SQL queries can be compared to saved query text, and if a match is found, the corresponding saved abstract plan is used to execute the query.
Abstract plans provide a means for system administrators and performance tuners to protect the overall performance of a server from changes to query plans. Changes in query plans can arise due to:
The main purpose of abstract plans is to provide a means to capture query plans before and after major system changes. You can then compare sets of before-and-after query plans to determine the effects of changes on your queries.
Abstract plans provide an alternative to options that must be specified in the batch or query to influence optimizer decisions. Using abstract plans, you can influence the optimization of a SQL statement without modifying the statement syntax. While matching query text to stored text requires some processing overhead, using a saved plan reduces query optimization overhead.
Relationship between query text and query plans
For most SQL queries, there are many possible query execution plans. SQL describes the desired result set, but does not describe how that result set should be obtained from the database.
There are many different possible join orders, and depending on the indexes that exist on the tables, many possible access methods, including table scans, index scans, and the reformatting strategy. Each join may use either a nested-loop join or a merge join. These choices are determined by the optimizer’s query costing algorithms, and are not included in or specified in the query itself.
When you capture the abstract plan, the query is optimized in the usual way, except that the optimizer also generates an abstract plan, and saves the query text and abstract plan in sysqueryplans.
Abstract plans can be full plans, describing all query processing steps and options, or they can be partial plans. A partial plan might specify that an index is to be used for the scan of a particular table, without specifying other access methods.
Abstract plan groups
By default there are two abstract plan groups:
ap_stdout, used by default to capture plans
ap_stdin, used by default for plan association
A system administrator or database owner can create additional plan groups, copy plans from one group to another, and compare plans in two different groups.
The capture of abstract plans and the association of abstract plans with queries always happens within the context of the currently active plan group. Users can use session-level set commands to enable plan capture and association.
Some of the ways abstract plan groups can be used are:
A query tuner can create abstract plans in a group created for testing purposes without affecting plans for other users on the system
Using plan groups, “before” and “after” sets of plans can be used to determine the effects of system or upgrade changes on query optimization.
Using set commands to capture and associate plans
At the session level, any user can enable and disable capture and use of abstract plans using the set plan dump and set plan load commands.
Enabling and disabling abstract plan modes takes effect at the end of the batch in which the command is included (similar to showplan). Therefore, change the mode in a separate batch before you run your queries:
Enabling plan capture mode with set plan dump
The set plan dump command activates and deactivates the capture of abstract plans. You can save the plans to the default group, ap_stdout, by using set plan dump with no group name:
set plan dump on
To start capturing plans in a specific abstract plan group, specify the group name. This example sets the group dev_plans as the capture group:
set plan dump dev_plans on
The group that you specify must exist before you issue the set command. The system procedure sp_add_qpgroup creates abstract plan groups; only the system administrator or database owner can create an abstract plan group. Once an abstract plan group exists, any user can dump plans to the group.
To deactivate the capturing of plans, use:
set plan dump off
You do not need to specify a group name to end capture mode. Only one abstract plan group can be active for saving or matching abstract plans at any one time. If you are currently saving plans to a group, turn off the plan dump mode, and re-enable it for the new group, as shown here:
set plan dump on /*save to the default group*/
go
/*some queries to be captured */
go
set plan dump off
go
set plan dump dev_plans on
go
/*additional queries*/
go
Associating queries with stored plans
The set plan load command activates and deactivates the association of queries with stored abstract plans.
To start the association mode using the default group, ap_stdin, use:
set plan load on
To enable association mode using another abstract plan group, specify the group name:
set plan load test_plans on
Only one abstract plan group can be active for plan association at one time. If plan association is active for a group, deactivate the current group and activate plan association for the new group, as shown here:
set plan load test_plans on
go
/*some queries*/
go
set plan load off
go
set plan load dev_plans on
go
Using show_abstract_plan to view plans
set option show_abstract_plan prints the optimal abstract plan currently running on the TDS connection. It prints the plan after optimization and before execution, and is the only set option show_ command that does not depend on trace flag 3604 or 3605.
Printing the final plan’s abstract plan is similar to viewing showplan output: it provides information to the user, but the abstract plan is not saved in sysqueryplans, and is not used if you use the abstract plan load mode.
This example shows the optimal abstract plan currently running on the TDS connection:
1> set option show_abstract_plan on
2> go
1> select r1, sum(s1)
2> from r, s
3> where r2=s2
4> group by r1
The Abstract Plan (AP) of the final query execution plan:
( group_sorted ( nl_join ( i_scan ir12 r ) ( i_scan is21 s ) ) )
( prop r (parallel 1 ) ( prefetch 2 ) ( lru ) )
( prop s ( parallel 1 ) ( prefetch 2 ) (lru ) )
To experiment with the optimizer behavior, this AP can be modified and then
passed to the optimizer using the PLAN clause:
SELECT/INSERT/DELETE/UPDATE ...
PLAN '( ... )'.
r1
----------- -----------
1 2
2 4
(2 rows affected)
Using showplan
When showplan is turned on, and abstract plan association mode has been enabled with set plan load, showplan prints the plan ID of the matching abstract plan at the beginning of the showplan output for the statement:
QUERY PLAN FOR STATEMENT 1 (at line 1).
Optimized using an Abstract Plan (ID : 832005995).
If you run queries using the plan clause added to a SQL statement, showplan displays:
Optimized using the Abstract Plan in the PLAN clause.
Using forceplan
If set forceplan on is in effect, and query association is also enabled for the session, forceplan is ignored if a full abstract plan is used to optimize the query. If a partial plan does not completely specify the join order:
First, the tables in the abstract plan are ordered, as specified.
The remaining tables are ordered as specified in the from clause.
The two lists of tables are merged.
Practical sample of getting, modifying and applying an Abstract Plan
The below sample will involve a query using a view with 3 tables we'll see how to get the original abstract plan, take a look at the original join order and then edit it to change the join order and finally how to associate the abstract plan with a query.
-- Object definitions
create table t1 (c1 int )
create table t2 (c2 int )
create table t3 (c3 int )
create view view_asis as
select c1 , c2 , c3 from t1 , t2 , t3
set statement_cache off
set option show_abstract_plan on -- enables abstract plan output
set showplan on
dbcc traceon(3604)
go
-- execute the query and getting the abstract plan
select * from view_asis
go
set option show_abstract_plan off
go
-- as shown showplan output describes the join order as t1->t2->t3
QUERY PLAN FOR STATEMENT 1 (at line 1).
Optimized using Serial Mode
STEP 1
The type of query is SELECT.
4 operator(s) under root
|ROOT:EMIT Operator (VA = 4)
|
| |N-ARY NESTED LOOP JOIN Operator (VA = 3) has 3 children.
| |
| | |SCAN Operator (VA = 0)
| | | FROM TABLE
| | | t1
| | | Table Scan.
| | | Forward Scan.
| | | Positioning at start of table.
| | | Using I/O Size 2 Kbytes for data pages.
| | | With LRU Buffer Replacement Strategy for data pages.
| |
| | |SCAN Operator (VA = 1)
| | | FROM TABLE
| | | t2
| | | Table Scan.
| | | Forward Scan.
| | | Positioning at start of table.
| | | Using I/O Size 2 Kbytes for data pages.
| | | With LRU Buffer Replacement Strategy for data pages.
| |
| | |SCAN Operator (VA = 2)
| | | FROM TABLE
| | | t3
| | | Table Scan.
| | | Forward Scan.
| | | Positioning at start of table.
| | | Using I/O Size 2 Kbytes for data pages.
| | | With LRU Buffer Replacement Strategy for data pages.
Original join order is t1 -> t2 ->t3 the new join order will be t3-> t1 ->t2
-- modify the join order shown in the abstract plan by simply changing the order of teh tables
-- original
( nl_join ( nl_join ( t_scan t1 ) ( t_scan t2 ) ) ( t_scan t3 ) )
-- new
( nl_join ( nl_join ( t_scan t3 ) ( t_scan t1 ) ) ( t_scan t2 ) )
-- execute the query forcing the new join order by using the PLAN clause
select * from view_asis
plan"( nl_join ( nl_join ( t_scan t3 ) ( t_scan t1 ) ) ( t_scan t2 ) )"
-- verify showplan has the new join order
STEP 1
The type of query is SELECT.
4 operator(s) under root
|ROOT:EMIT Operator (VA = 4)
|
| |N-ARY NESTED LOOP JOIN Operator (VA = 3) has 3 children.
| |
| | |SCAN Operator (VA = 0)
| | | FROM TABLE
| | | t3
| | | Table Scan.
| | | Forward Scan.
| | | Positioning at start of table.
| | | Using I/O Size 2 Kbytes for data pages.
| | | With LRU Buffer Replacement Strategy for data pages.
| |
| | |SCAN Operator (VA = 1)
| | | FROM TABLE
| | | t1
| | | Table Scan.
| | | Forward Scan.
| | | Positioning at start of table.
| | | Using I/O Size 2 Kbytes for data pages.
| | | With LRU Buffer Replacement Strategy for data pages.
| |
| | |SCAN Operator (VA = 2)
| | | FROM TABLE
| | | t2
| | | Table Scan.
| | | Forward Scan.
| | | Positioning at start of table.
| | | Using I/O Size 2 Kbytes for data pages.
| | | With LRU Buffer Replacement Strategy for data pages.
c1 c2 c3
-- turn off showplan
set showplan off
go
Now new abstract group will be created to store the abstract plan
-- create a new AP group and enable plan capture
sp_add_qpgroup new_plans
go
set plan dump new_plans on
go
-- execute the query and turn off plan capture mode
select * from view_asis
plan"( nl_join ( nl_join ( t_scan t3 ) ( t_scan t1 ) ) ( t_scan t2 ) )"
go
set plan dump off
go
-- verify creation of AP using the sp_find_qplan to verify the abstract plan creation
sp_find_qplan "%t1%"
gid id text
----------- ----------- ---------------------------------------------------------------------------
3 1872006669 select * from view_asis
3 1872006669 ( nl_join ( nl_join ( t_scan t3 ) ( t_scan t1 ) ) ( t_scan t2 ) )
(return status = 0)
-- enabled load mode with this step we are enabling the use of the abstract plan from the new_plans group
set plan load new_plans on
-- execute query and verify plan was correctly chossen
set showplan on
select * from view_asis
-- As shown in the showplan output ansd abstract plan is used and teh desire join order
QUERY PLAN FOR STATEMENT 1 (at line 1).
Optimized using Serial Mode
Optimized using an Abstract Plan (ID : 1872006669).
STEP 1
The type of query is SELECT.
4 operator(s) under root
|ROOT:EMIT Operator (VA = 4)
|
| |N-ARY NESTED LOOP JOIN Operator (VA = 3) has 3 children.
| |
| | |SCAN Operator (VA = 0)
| | | FROM TABLE
| | | t3
| | | Table Scan.
| | | Forward Scan.
| | | Positioning at start of table.
| | | Using I/O Size 2 Kbytes for data pages.
| | | With LRU Buffer Replacement Strategy for data pages.
| |
| | |SCAN Operator (VA = 1)
| | | FROM TABLE
| | | t1
| | | Table Scan.
| | | Forward Scan.
| | | Positioning at start of table.
| | | Using I/O Size 2 Kbytes for data pages.
| | | With LRU Buffer Replacement Strategy for data pages.
| |
| | |SCAN Operator (VA = 2)
| | | FROM TABLE
| | | t2
| | | Table Scan.
| | | Forward Scan.
| | | Positioning at start of table.
| | | Using I/O Size 2 Kbytes for data pages.
| | | With LRU Buffer Replacement Strategy for data pages.
c1 c2 c3
----------- ----------- -----------
(0 rows affected)