Sponsored by PRISE Ltd.
www.prisetools.com
www.prisetools.com
Analyze "Index usage" in DBQL
Please note that the solutions found in the article works on the DBQL logs, which covers only that users' activity, for whom the logging is switched on. "Object" option in DBQL is required "on" to use the scripts provided.
About Indices
Teradata provides possibility of creating INDEX objects for allowing alternative access path to the data records. They are quite different structures then the good old B*Tree or Bitmap indices (common in non-MPP RDBMSes)The main goal of the index objects is to improve data access performance in exchange for storage and maintenance processing capacity.
Having indices is not free (storage and maintenance resources), those ones that bring not enough gain is better being dropped.
Index usage footprint in DBQL
If a query uses an index for accessing the data it is declared in the "explain text", and also registered in the DBQL: dbqlobjtbl. The appearance type of indices depend on the type of index. In case of primary/secondary index only IndexId and the columns of the index are registered, while join/hash indices appear like a regular table: at database, object and column levels all.If the join/hash index is covering, the base table may not be listed in the DBQL objects, therefore be careful if analyze table usage from DBQLobjtbl.
I recommend to use PRISE Tuning Assistant to easily find all type of access to a table data.
Examples
Primary index access (2 columns):
Plan:
1) First, we do a single-AMP RETRIEVE step from d01.z by way of the
primary index "d01.z.i = 1, d01.z.j = 1" with no residual
DBQLobjtbl:
... | ObjectDatabaseName | ObjectTableName | ObjectColumnName | ObjectNum | ObjectType | ... |
... | D01 | Z | i | 1 | Idx | ... |
... | D01 | Z | j | 1 | Idx | ... |
Plan:
3) We do an all-AMPs RETRIEVE step from d01.x by way of index # 4
without accessing the base table "d01.x.j = 1" with no residual
DBQLobjtbl:
... | ObjectDatabaseName | ObjectTableName | ObjectColumnName | ObjectNum | ObjectType | ... |
... | D01 | X | 4 | Idx | ... |
Join index:
create join index d01.ji as sel b from d01.q primary index (b);
select b from d01.q where a=1;
Plan:
1) First, we do a single-AMP RETRIEVE step from D01.JI by way of the
primary index "D01.JI.a = 1" with no residual conditions into
DBQLobjtbl:
... | ObjectDatabaseName | ObjectTableName | ObjectColumnName | ObjectNum | ObjectType | ... |
... | D01 | JI | 0 | Jix | ... | |
... | D01 | JI | a | 1 | Idx | ... |
... | D01 | JI | b | 1026 | Col | ... |
- ObjectNum identifies the index (refers to dbc.indices.Indexnumber)
- As many rows appeas as many columns the index has
- Eg. in V13.10 Teradata Express the single column secondary index lacks the column name in the logs
Analyzing DBQL data
Prepare data
CREATE VOLATILE TABLE DBQLIdx_tmp1 AS (
SELECT databasename,tablename,indexnumber,indextype,uniqueflag,Columnposition,Columnname
, SUM (1) OVER (partition BY databasename,tablename,indexnumber ORDER BY Columnname ROWS UNBOUNDED PRECEDING) ABCOrder
FROM dbc.indices WHERE indextype IN ('K','P','Q','S','V','H','O','I')
) WITH DATA
PRIMARY INDEX (databasename,tablename,indexnumber)
ON COMMIT PRESERVE ROWS
;
CREATE VOLATILE TABLE DBQLIdx_tmp2 AS (
WITH RECURSIVE idxs (Databasename,Tablename,Indexnumber,Indextype,Uniqueflag,Indexcolumns,DEPTH)
AS (
SELECT
databasename,tablename,indexnumber,indextype,uniqueflag,TRIM (Columnname) (VARCHAR (1000)),ABCorder
FROM DBQLIdx_tmp1 WHERE ABCorder = 1
UNION ALL
SELECT
b.databasename,b.tablename,b.indexnumber,b.indextype,b.uniqueflag,b.Indexcolumns||','||TRIM (a.Columnname),a.ABCOrder
FROM DBQLIdx_tmp1 a
JOIN idxs b ON a.databasename = b.databasename AND a.tablename = b.tablename AND a.indexnumber = b.indexnumber AND a.ABCOrder = b.Depth + 1
)
SELECT databasename db_name,tablename table_name,indextype,uniqueflag,indexcolumns
,indexnumber
,CASE WHEN uniqueflag = 'Y' AND indextype IN ('P','Q','K') THEN 'UPI'
WHEN uniqueflag = 'N' AND indextype IN ('P','Q') THEN 'NUPI'
WHEN uniqueflag = 'Y' AND indextype IN ('S','V','H','O') THEN 'USI'
WHEN uniqueflag = 'N' AND indextype IN ('S','V','H','O') THEN 'NUSI'
WHEN indextype = 'I' THEN 'O-SI'
ELSE NULL
END Index_code
FROM idxs
QUALIFY SUM (1) OVER (partition BY db_name,table_name,indexnumber ORDER BY DEPTH DESC ROWS UNBOUNDED PRECEDING) = 1
) WITH DATA
PRIMARY INDEX (db_name,table_name)
ON COMMIT PRESERVE ROWS
;
UPDATE a
FROM DBQLIdx_tmp2 a,DBQLIdx_tmp2 b
SET Index_code = 'PK'
WHERE a.db_name = b.db_name
AND a.table_name = b.table_name
AND a.Index_code = 'UPI'
AND a.indextype = 'K'
AND b.Index_code = 'NUPI'
AND b.indextype <> 'K'
;
Report: How many times have the indices been used?
You may need to modify the script:
SELECT- Date filtering (use between for interval)
- Online/archived DBQL: use commented section for archived
COALESCE(usg.objectdatabasename,idx.db_name) db
, COALESCE(usg.objecttablename,idx.table_name) tbl
, COALESCE(usg.ObjectNum,idx.IndexNumber) idxNo
, idx.Index_code
, idx.Indexcolumns Index_columnss
, coalesce(usg.drb,0) Nbr_of_usg
FROM
(SELECT objectdatabasename,objecttablename,objecttype,ObjectNum,COUNT (*) drb
-- Archived DBQL
-- FROM dbql_arch.dbqlobjtbl_hst WHERE logdate = '2014-02-20' (date)
-- Online DBQL
FROM dbc.dbqlobjtbl WHERE cast(collecttimestamp as char(10)) = '2014-02-20'
AND objecttablename IS NOT NULL
AND ((objecttype IN ('JIx','Hix') AND objectcolumnname IS NULL)
OR
(objecttype IN ('Idx'))
)
AND objectnum <> 1
GROUP BY 1,2,3,4
) usg
FULL OUTER JOIN
( SELECT db_name,table_name,Indextype,Uniqueflag,indexcolumns,Indexnumber,Index_code
FROM DBQLIdx_tmp2 a WHERE indextype NOT IN ('P','Q','K')
union all
SELECT databasename,tablename,tablekind,cast(null as char(1))
,cast(null as varchar(1000)),cast(null as smallint)
,case when tablekind='I' then 'JIX' else 'HIX' end from dbc.tables where tablekind in ('I','N')
) idx ON usg.objectdatabasename = idx.db_name
AND usg.objecttablename = idx.table_name
AND ((usg.ObjectNum = idx.IndexNumber) or usg.objecttype IN ('JIx','Hix'))
ORDER BY 6 DESC
;
Sponsored by PRISE Ltd.
www.prisetools.com
www.prisetools.com
Thank you Akos, I was looking for some materials relative to DBQL and now I am finding here. Good learning :)
ReplyDelete-- Cheeli
You are welcome, Cheeli,
ReplyDeleteIf you want to extract more valueable information from DBQL data in a pretty comfortable way, try PRISE Tuning Assistant, you can download it from here:
http://www.prisetools.com/free-trial
I am delighted to have this easy-to-go tool with all magnificent features.
ReplyDelete-- Cheeli