Documente Academic
Documente Profesional
Documente Cultură
Joe Ramon
Agenda
What is the EXPLAIN facility?
Where does the EXPLAIN output come FROM?
What does the Optimizer need to build a plan?
What does the EXPLAIN terminology mean?
What can be learned by reading the EXPLAIN text?
What can be done to influence the Optimizer?
Summary
What is EXPLAIN?
The EXPLAIN facility provides an "English" translation of
the plan the SQL Optimizer develops to service a
request.
May be used on any SQL statement, except EXPLAIN
itself.
Look for key words AND phrases
Execution time AND row count estimates depend on:
> Are statistics collected?
Actual execution time depends on:
> Is DBS processing other requests?
> Is channel or network busy?
SQL REQUEST
DD SYNTAXER
Dbase
AccessRights DD Cache RESOLVER
RoleGrants (V2R5)
TVM
TVFields SECURITY
Indexes
GENERATOR
APPLY
DISPATCHER
AMP
Information Known to Optimizer
By default, Teradata chooses an AMP for random AMP (or dynamic) data
sampling.
EXPLAIN Example
EXPLAIN
SELECT Last_Name, First_Name, Dept_Name, Job_Desc
FROM Employee E
INNER JOIN Department D ON E.Dept_Number = D.Dept_Number
INNER JOIN Job J ON E.Job_code = J.Job_code
ORDER BY 3, 1, 2;
EXPLAIN Example (cont.)
1) First, we lock a distinct TFACT."pseudo table" for read on a RowHash to prevent global
deadlock for TFACT.E.
2) Next, we lock a distinct TFACT."pseudo table" for read on a RowHash to prevent global
deadlock for TFACT.J.
3) We lock a distinct TFACT."pseudo table" for read on a RowHash to prevent global deadlock
for TFACT.D.
4) We lock TFACT.E for read, we lock TFACT.J for read, and we lock TFACT.D for read.
5) We execute the following steps in parallel.
1) We do an all-AMPs RETRIEVE step from TFACT.D by way of an all-rows scan with no
residual conditions into Spool 2 (all_amps), which is duplicated on all AMPs. The size
of Spool 2 is estimated with high confidence to be 19,642 rows (726,754 bytes). The
estimated time for this step is 0.02 seconds.
2) We do an all-AMPs RETRIEVE step from TFACT.J by way of an all-rows scan with no
residual conditions into Spool 3 (all_amps), which is duplicated on all AMPs. Then we
do a SORT to order Spool 3 by the hash code of (TFACT.J.Job_Code). The size of Spool
3 is estimated with high confidence to be 12,166 rows (450,142 bytes). The estimated
time for this step is 0.01 seconds.
6) We do an all-AMPs JOIN step from Spool 2 (Last Use) by way of an all-rows scan, which is
joined to TFACT.E by way of an all-rows scan with a condition of ("NOT (TFACT.E.Job_Code
IS NULL)"). Spool 2 and TFACT.E are joined using a single partition hash_ join, with a join
: :
8) Finally, we send out an END TRANSACTION step to all AMPs involved in processing the
request.
-> The contents of Spool 1 are sent back to the user as the result of statement 1. The total
estimated time is 0.14 seconds.
EXPLAIN Terminology
First PE PE Second
request request
Determine
Table ID hash
:
3) We do a BMSMS (bit map set manipulation) step that builds a bit map for TFACT.Employee
by way of index # 4 "TFACT.E.Job_Code = 3500" which is placed in Spool 2. The estimated
time for this step is 0.01 seconds.
4) We do an all-AMPs RETRIEVE step from TFACT.E by way of index # 8
TFACT.E.Dept_Number = 1310" and the bit map in Spool 2 (Last Use) with a residual
condition of ("TFACT.E.Job_Code = 3500") into Spool 1 (group_amps), which is built locally
on the AMPs. The size of Spool 1 is estimated with low confidence to be 60 rows (4620
bytes). The estimated time for this step is 0.02 seconds.
5) Finally, we send out an END TRANSACTION step to all AMPs involved in processing the
request.
-> The contents of Spool 1 are sent back to the user as the result of statement 1. The total
estimated time is 0.03 seconds.
Note:
Statistics were collected on the NUSIs Job_Code and Dept_Number.
Synchronized Scanning
In the case of multiple users that access the same table at the same time,
the system can do a synchronized scan (sync scan) on the table.
112747
Query 1766
1 100766 3001 Frankel Allan
034982 2212
Begins 106363 3005 Bench John
310229 2231 108222 3100 Palmer Carson
209181 1235 108221 3001 Smith Buster
123881 2433 101433 3007 Walton Sam
223431 2500 105200 3101 Brooks Steve
221015 1019 108222 Query
3199
2 Woods Tiger
121332 2281 101281 Begins
3007 Walton John
118314 2100 101100 3002 Ramon Anne
104631 1279 100279 3002 Roberts Julie
210110 1201 101222 3003 Douglas Michael
210001 1205 105432 3022 Morgan Joe
100076 1011 104321 3021 Anderson Sparky
Query 3
100045 1012 101231 3087 Michelson Phil
Begins
319116 1219 121871 3025 Crawford Cindy
: : : : : :
: : : : : :
Synchronized Scanning (cont.)
EXPLAIN SELECT * FROM daily_sales ORDER BY 1;
:
3) We do an all-AMPs RETRIEVE step from TFACT.daily_sales by way of an all-rows scan
with no residual conditions into Spool 1 (group_amps), which is built locally on the
AMPs. Then we do a SORT to order Spool 1 by the sort key in spool field1
(TFACT.daily_sales.Item_id). The input table will not be cached in memory, but it is
eligible for synchronized scanning. The result spool file will not be cached in memory.
The size of Spool 1 is estimated with high confidence to be 76,685 rows (2,530,605 bytes).
The estimated time for this step is 0.09 seconds.
:
. . . with no confidence . . .
One input relation has no confidence.
Statistics do not exist for either join field.
Timings:
> Used to determine the lowest cost plan
> Total cost generated if all processing steps have assigned cost
> Not intended to predict wall-clock time, useful for comparisons
Miscellaneous Notes:
> Estimates too large to display show 3 asterisks (***).
> The accuracy of the time estimate depends upon the accuracy of
the row estimate.
Optimized INSERT/SELECT
INSERT/SELECT is the process of SELECTing data FROM one
table and using it as input to be inserted into another table.
EXPLAIN
INSERT INTO Employee_CharPI SELECT * FROM Employee;
:
4) We do an all-AMPs RETRIEVE step from TFACT.Employee by way of an all-rows
scan with no residual conditions into Spool 1 (all_amps), which is redistributed
by the hash code of (TFACT.Employee.Employee_Number (CHAR(10),
CHARACTER SET LATIN, NOT CASESPECIFIC, FORMAT '-(10)9')(CHAR(10),
CHARACTER SET LATIN, NOT CASESPECIFIC, NAMED Employee_Number,
FORMAT 'X(10)', NULL)) to all AMPs. Then we do a SORT to order Spool 1 by
row hash. The size of Spool 1 is estimated with high confidence to be 26,000
rows (1,950,000 bytes). The estimated time for this step is 0.06 seconds.
5) We do an all-AMPs MERGE into TFACT.Employee_CharPI from Spool 1 (Last
Use). The size is estimated with high confidence to be 26,000 rows. The
estimated time for this step is 1.38 seconds.
6) We spoil the parser's dictionary cache for the table.
7) Finally, we send out an END TRANSACTION step to all AMPs involved in
processing the request.
-> No rows are returned to the user as the result of statement 1.
Unexpected Full Table Scan
EXPLAIN
SELECT * FROM Employee_CharPI WHERE employee_number = 1104066 ;
Joe Ramon
Agenda
Teradata Optimizer
Statistics basically tell the Optimizer how many rows/value there are.
The Optimizer uses statistics to plan the best way to access data.
Stale statistics may mislead the Optimizer into poor decisions.
Helpful in accessing a column or index with uneven value distribution.
NUSI Bit Mapping is much more likely to be considered if there are
collected statistics.
Statistics remain valid across a reconfiguration of the system.
COLLECT/DROP STATISTICS places an access lock on the data table
and a row-hash write lock on DBC.TVFields or DBC.Indexes.
DBC.TVFields holds statistics collected for single column or
single column index
DBC.Indexes holds statistics collected for multi-column or multi-
column index
Summary Section
(Interval #0) 200 (or 100) Intervals
Summary Section
(Interval #0) 200 Intervals
Summary Section
(Interval #0) 198 Intervals
~
Interval Interval #1 Interval #2 Interval #3
#0
~
SQL Statement Optimizer assumes
SELECT * FROM tabx WHERE col1 = 1200; 400
SELECT * FROM tabx WHERE col1 = 1075; 180
SELECT * FROM tabx WHERE col1 = 1492; 7
SELECT * FROM tabx WHERE col1 = 1300; 10
SELECT * FROM tabx WHERE col1 BETWEEN 1150 AND 1250; 700
SELECT * FROM tabx WHERE col1 BETWEEN 1150 AND 1550; 1350
Merge Joins
Join costs increase with the number of rows which must be moved AND sorted
A join plan for the same query will vary over time as the table demographics change
Merge Join and Redistribution
Show an employees name AND their manager's name.
EXPLAIN
SELECT M.Last_Name, M.First_Name,
E.Last_Name, E.First_Name
FROM Employee M
INNER JOIN Employee E
ON M.Employee_Number = E.Emp_Mgr_Number;
: (Locking step)
2) Next, we lock TFACT.E for read.
3) We do an all-AMPs RETRIEVE step from TFACT.E by way of an all-rows scan with a condition
of ("NOT (TFACT.E.Emp_Mgr_Number IS NULL)") into Spool 2 (all_amps), which is
redistributed by hash code of (TFACT.E.Emp_Mgr_Number) to all AMPs. Then we do a SORT
to order Spool 2 by row hash. The size of Spool 2 is estimated with high confidence to be
27,000 rows (1,215,000 bytes). The estimated time for this step is 0.05 seconds.
4) We do an all-AMPs JOIN step from TFACT.M by way of a RowHash match scan with no
residual conditions, which is joined to Spool 2 (Last Use) by way of a RowHash match scan.
TFACT.M and Spool 2 are joined using a merge join, with a join condition of
("TFACT.M.Employee_Number = Emp_Mgr_Number"). The result goes into Spool 1
(group_amps), which is built locally on the AMPs. Then we do a SORT to order Spool 1 by
the sort key in spool field1 (TFACT.M.Last_Name, TFACT.E.Last_Name). The size of Spool 1
is estimated with low confidence to be 27,000 rows (2,079,000 bytes). The estimated time for
this step is 0.05 seconds.
:
: (Locking steps)
4) We do an all-AMPs RETRIEVE step from TFACT.D by way of an all-rows scan with no residual
conditions into Spool 2 (all_amps), which is duplicated on all AMPs. The size of Spool 2 is
estimated with high confidence to be 19,642 rows (726,754 bytes). The estimated time for this
step is 0.02 seconds.
5) We do an all-AMPs JOIN step from Spool 2 (Last Use) by way of an all-rows scan, which is
joined to TFACT.E by way of an all-rows scan. Spool 2 and TFACT.E are joined using a single
partition hash_join, with a join condition of ("TFACT.E.Dept_Number = Dept_Number"). The
result goes into Spool 1 (group_amps), which is built locally on the AMPs. Then we do a
SORT to order Spool 1 by the sort key in spool field1 (TFACT.E.Last_Name,
TFACT.E.First_Name). The size of Spool 1 is estimated with low confidence to be 27,000 rows
(1,863,000 bytes). The estimated time for this step is 0.06 seconds.
:
Exclusion Merge Join
Show all employees who have no assigned phone.
EXPLAIN SELECT employee_number FROM Employee
EXCEPT SELECT employee_number FROM Emp_Phone;
Product Joins
EXPLAIN SELECT dept_name, last_name, first_name
FROM Employee E INNER JOIN Department D
ON (E.dept_number = D.dept_number
OR E.employee_number = D.dept_mgr_number);
4) We do an all-AMPs RETRIEVE step from TFACT.D by way of an all-rows scan with
no residual conditions into Spool 2 (all_amps), which is duplicated on all AMPs.
The size of Spool 2 is estimated with high confidence to be 19,642 rows (805,322
bytes). The estimated time for this step is 0.02 seconds.
5) We do an all-AMPs JOIN step from Spool 2 (Last Use) by way of an all-rows scan,
which is joined to TFACT.E by way of an all-rows scan with no residual
conditions. Spool 2 and TFACT.E are joined using a product join, with a join
condition of ("(TFACT.E.Dept_Number = Dept_Number) OR
(TFACT.E.Employee_Number = Dept_Mgr_Number)"). The result goes into Spool
1 (group_amps), which is built locally on the AMPs. The size of Spool 1 is
estimated with low confidence to be 28,403 rows (1,959,807 bytes). The estimated
time for this step is 1.58 seconds.
6) Finally, we send out an END TRANSACTION step to all AMPs involved in
processing the request.
-> The contents of Spool 1 are sent back to the user as the result of statement 1.
The total estimated time is 1.60 seconds.
Cartesian Product Join
EXPLAIN
SELECT E.employee_number
,E.last_name
,E.first_name
,D.dept_name
,P.phone_number
FROM Employee E, Department D, Emp_Phone P;
To maintain uniqueness on the Primary Index, you can create a USI on the
PI (e.g., Claim_Number). This allows faster access to specific claim rows.
Note:
The ranges of dates includes 3 complete partitions and a portion of a partition.
Join Indexes
A Join Index is an optional index which may be created by the user.
The basic types of Join Indexes will be described first.
How many valid customers have assigned orders on May 16, 2004?
SELECT o_orderdate
,COUNT (c_custid)
FROM Customer
INNER JOIN Orders
ON c_custid = o_custid
WHERE o_orderdate = '2004-05-16'
GROUP BY 1;
Name the valid customers and their addresses who have open orders on
May 16, 2004?
SELECT c_custid,
c_lname,
c_address,
o_orderdate
FROM Customer C
INNER JOIN Orders O
ON c_custid = o_custid
WHERE o_orderstatus = 'O'
AND o_orderdate = '2004-05-16'
ORDER BY 1;
Note:
The join index eliminated the need to redistribute the Orders table into spool.
:
3) We do a single-AMP RETRIEVE step from TFACT.Orders_GI by way of the
primary index "TFACT.Orders_GI.o_custid = 1500" with no residual conditions
into Spool 2 (group_amps), which is redistributed by hash code to all AMPs.
Then we do a SORT to order Spool 2 by the sort key in spool field1. The size of
Spool 2 is estimated with high confidence to be 14 rows. The estimated time
for this step is 0.00 seconds.
4) We do a group-AMPs JOIN step from Spool 2 (Last Use) by way of an all-rows
scan, which is joined to TFACT.Orders. Spool 2 and TFACT.Orders are joined
using a row id join, with a join condition of ("Field_1 = TFACT.Orders.RowID").
The result goes into Spool 1 (group_amps), which is built locally on the AMPs.
The size of Spool 1 is estimated with index join confidence to be 4 rows. The
estimated time for this step is 0.08 seconds.
:
Summary
Use EXPLAIN:
to get costs of different approaches
to find unexpected product joins
for best approach for using join indexes
ensure that sync scanning is enabled
Collect statistics:
On non-unique indexes
On non-index join columns
On small tables
to get better costs
to get better plans
Or