Home » Databases » Sybase » ASE » Ed Barlow Procedures: sp__montableusage updated for SAP Sybase ASE 15 and higher

Ed Barlow Procedures: sp__montableusage updated for SAP Sybase ASE 15 and higher

Back in 2006, Mich Talebzadeh createdSAP Sybase the sp__montableusage stored procedure for reporting on table and index usage based on the MDA tables in Sybase ASE 12.5x using the MDA tables as part of the excellent Extended Stored Procedures by Ed Barlow (AKA the Ed Barlow Stored Procedures). In v15, Sybase deprecated the rowcnt() and reserved_pgs() functions that was used to report on the estimated number of rows in favor of the row_count() and reserved_pages() functions respectfully. I’ve updated the stored procedure to use the row_count() and reserved_pages() functions.

$ diff sp__montableusage.12 sp__montableusage.15
10,15c10,17
< ------------------------------------------------------------------------------------------------
< -- Vers|  Date  |      Who           | DA | Description
< -------+--------+--------------------+----+-----------------------------------------------------
< -- 1.0 |07/04/06|  Mich Talebzadeh   |    | Stored procedure giving comprehensive report
< --     |        |                    |    | about table and index usage based on the MDA tables
< -------+--------+--------------------+----+-----------------------------------------------------
---
> --------------------------------------------------------------------------------------------------
> -- Vers|   Date   |      Who           | DA | Description
> -------+----------+--------------------+----+-----------------------------------------------------
> -- 1.1 |11/18/2013|  Jason Froebe      |    | Replace rowcnt with row_count() and reserved_pgs with
> --     |          |                    |    | reserved_pages()
> -- 1.0 |07/04/2006|  Mich Talebzadeh   |    | Stored procedure giving comprehensive report
> --     |          |                    |    | about table and index usage based on the MDA tables
> -------+----------+--------------------+----+-----------------------------------------------------
27,28c29,30
< rowtotal = rowcnt(i.doampg),
<         reserved = (reserved_pgs(i.id, i.doampg) + reserved_pgs(i.id, i.ioampg)) * (low / 1024)
---
>         rowtotal = row_count(db_id(), o.id),
>         reserved = reserved_pages(db_id(), o.id, i.indid) * (low / 1024)

use sybsystemprocs
go
IF EXISTS(SELECT 1 FROM sysobjects WHERE type = ‘P’ AND name = ‘sp__montableusage’)
BEGIN
DROP PROCEDURE sp__montableusage
END
go
create procedure sp__montableusage
as
————————————————————————————————–
— Vers| Date | Who | DA | Description
——-+———-+——————–+—-+—————————————————–
— 1.1 |11/18/2013| Jason Froebe | | Replace rowcnt with row_count() and reserved_pgs with
— | | | | reserved_pages()
— 1.0 |07/04/2006| Mich Talebzadeh | | Stored procedure giving comprehensive report
— | | | | about table and index usage based on the MDA tables
——-+———-+——————–+—-+—————————————————–

begin
set nocount on

— First of all work out the table rows and sizes (reserved)

select
“Owner” = user_name(o.uid),
TableName = o.name,
IndexName = i.name,
low = d.low,
rowtotal = row_count(db_id(), o.id),
reserved = reserved_pages(db_id(), o.id, i.indid) * (low / 1024)
into #t1
from sysobjects o, sysindexes i, master.dbo.spt_values d
where
o.type = ‘U’
and i.id = o.id
and d.number = 1
and d.type = “E”

select distinct
Owner,
TableName,
RowTotal = convert(char(11), sum(rowtotal)),
Reserved = sum(reserved)
into #table_size
from #t1
group by Owner, TableName

— Identify tables accessed with a table scan
SELECT
“Owner” = user_name(o.uid),
“TableName” = o.name,
“LogicalReads” = m.LogicalReads,
“PagesRead” = m.PagesRead,
“WhenLastUsed” = m.LastUsedDate,
“Used” = m.UsedCount
INTO #tabscan
from
sysobjects o,
master..monOpenObjectActivity m
where
o.type = ‘U’
and o.id = m.ObjectID
and m.IndexID = 0
and m.DBID = db_id()
and object_name(m.ObjectID, m.DBID) not like ‘sa_%’
and object_name(m.ObjectID, m.DBID) not like ‘%__sa%’
and object_name(m.ObjectID, m.DBID) not like ‘rs_%’
and m.UsedCount > 0

print “”
print ‘Tables accessed with Table scans ONLY, no index usage’
print “”
SELECT
“TableName” = substring(t.Owner+”.”+t.TableName, 1, 30),
“Rows” = convert(numeric(10,0),s.RowTotal),
“Size/KB” = convert(numeric(10,0),s.Reserved),
“LogicalReads” = t.LogicalReads,
“PagesRead” = t.PagesRead,
“Table scanned” = str(t.Used, 8, 0),
“When last table scanned” = t.WhenLastUsed
FROM
#tabscan t,
#table_size s
WHERE
t.Owner = s.Owner
and t.TableName = s.TableName
and not exists (select 1 from master..monOpenObjectActivity m
where object_name(m.ObjectID, m.DBID) = t.TableName
and object_name(m.ObjectID, m.DBID) = s.TableName
and m.DBID = db_id()
and m.IndexID > 0
and m.LastUsedDate is not NULL)
ORDER BY
t.Owner,
t.TableName


— Identify tables with no DML

SELECT
“Owner” = user_name(o.uid),
“TableName” = o.name,
“LogicalReads” = m.LogicalReads,
“LockRequests” = m.LockRequests,
“Operations” = m.Operations,
“Selected” = m.OptSelectCount,
“WhenLastSelected” = m.LastOptSelectDate,
“Used” = m.UsedCount,
“WhenLastUsed” = m.LastUsedDate
INTO
#dormant
from
sysobjects o,
master..monOpenObjectActivity m
where
object_name(m.ObjectID, m.DBID) = o.name
and o.type = ‘U’
and o.id = m.ObjectID
and m.IndexID = 0 — Only tables!
and m.DBID = db_id()
and object_name(m.ObjectID, m.DBID) not like ‘sa_%’
and object_name(m.ObjectID, m.DBID) not like ‘%__sa%’
and object_name(m.ObjectID, m.DBID) not like ‘rs_%’
and m.RowsInserted = 0
and m.RowsUpdated = 0
and m.RowsDeleted = 0

PRINT “”
PRINT “Displaying dormant tables with no DML activity, table scan or index usage”
PRINT “”
SELECT
“TableName” = substring(t.Owner+”.”+t.TableName, 1, 30),
“Rows” = convert(numeric(10,0),s.RowTotal),
“Size/KB” = convert(numeric(10,0),s.Reserved),
“LogicalReads” = t.LogicalReads,
“LockRequests” = t.LockRequests
FROM
#dormant t,
#table_size s
WHERE
t.Owner = s.Owner
and t.TableName = s.TableName
and t.WhenLastUsed is NULL — table has never been used by the optimiser
— and no index of this table has been used by the optimiser
and not exists (select 1 from master..monOpenObjectActivity m
where object_name(m.ObjectID, m.DBID) = t.TableName
and object_name(m.ObjectID, m.DBID) = s.TableName
and m.DBID = db_id()
and m.IndexID > 0
and m.LastUsedDate is not NULL)
ORDER BY
t.Owner,
t.TableName


— Identify tables with DML activity

SELECT
“Owner” = user_name(o.uid),
“TableName” = o.name,
“LogicalReads” = m.LogicalReads,
“LockRequests” = m.LockRequests,
“Operations” = m.Operations,
“Selected” = m.OptSelectCount,
“WhenLastSelected” = m.LastOptSelectDate,
“Used” = m.UsedCount,
“WhenLastUsed” = m.LastUsedDate,
“Inserted” = m.RowsInserted,
“Updated” = m.RowsUpdated,
“Deleted” = m.RowsDeleted
INTO
#temp
from
sysobjects o,
master..monOpenObjectActivity m
where
object_name(m.ObjectID, m.DBID) = o.name
and o.type = ‘U’
and o.id = m.ObjectID
and m.IndexID = 0
and m.DBID = db_id()
and object_name(m.ObjectID, m.DBID) not like ‘sa_%’
and object_name(m.ObjectID, m.DBID) not like ‘%__sa%’
and object_name(m.ObjectID, m.DBID) not like ‘rs_%’
and (m.RowsInserted > 0 or m.RowsUpdated > 0 or m.RowsDeleted > 0)

SELECT
“TableName” = object_name(m.ObjectID, m.DBID),
“IndexName” = i.name,
“Selected” = m.OptSelectCount,
“WhenLastSelected” = m.LastOptSelectDate,
“Used” = m.UsedCount,
“WhenLastUsed” = m.LastUsedDate
into #used
from master..monOpenObjectActivity m,
sysindexes i
where
m.IndexID > 0
and m.IndexID <> 255 — ignore text, image data chain
and m.IndexID = i.indid
and m.ObjectID = i.id
and m.DBID = db_id()
print “”
if exists(select 1 from #used where Selected = 0 and Used = 0)
begin
print “”
print ‘Indexes never selected or used by the optimizer’
print “”
select
“TableName” = substring(i.Owner+”.”+i.TableName, 1, 30),
u.IndexName,
“IndexSize/KB” = i.reserved,
u.Selected,
u.Used
from #used u,
#t1 i
where u.TableName = i.TableName
and u.IndexName = i.IndexName
and u.Selected = 0 and u.Used = 0
order by u.TableName,
u.IndexName
end
if exists(select 1 from #used where Selected > 0 and Used = 0)
begin
print “”
print ‘Indexes selected by the optimizer but never used in query’
print “”
select
“TableName” = substring(i.Owner+”.”+i.TableName, 1, 30),
u.IndexName,
“IndexSize/KB” = i.reserved,
u.Selected,
“When Last selected” = u.WhenLastSelected
from #used u,
#t1 i
where u.TableName = i.TableName
and u.IndexName = i.IndexName
and u.Selected > 0 and u.Used = 0
order by u.TableName,
u.IndexName
end
if exists(select 1 from #used where Selected = 0 and Used > 0)
begin
print “”
print ‘Indexes Used by the optimizer but never selected’
print “”
select
“TableName” = substring(i.Owner+”.”+i.TableName, 1, 30),
u.IndexName,
“IndexSize/KB” = i.reserved,
u.Selected
from #used u,
#t1 i
where u.TableName = i.TableName
and u.IndexName = i.IndexName
and u.Selected = 0 and u.Used > 0
order by u.TableName,
u.IndexName
end
PRINT “”
PRINT “Displaying tables with DML activity”
PRINT “”
SELECT
“TableName” = substring(t.Owner+”.”+t.TableName, 1, 30),
“Rows” = convert(numeric(10,0),s.RowTotal),
“Size/KB” = convert(numeric(10,0),s.Reserved),
t.Inserted,
t.Updated,
t.Deleted,
t.LockRequests,
“SUM DML ACTIVITY/ROWS ” =
CASE
WHEN t.Inserted+t.Updated+t.Deleted > 0 and convert(numeric(10,0),s.RowTotal) > 0
THEN convert(varchar(9),(t.Inserted+t.Updated+t.Deleted)/convert(numeric(10, 0),s.RowTotal))
WHEN t.Inserted+t.Updated+t.Deleted > 0 and convert(numeric(10,0),s.RowTotal) = 0
THEN ” ==> Update stats advisable”
END
FROM
#temp t,
#table_size s
WHERE
t.Owner = s.Owner
and t.TableName = s.TableName
ORDER BY
t.Owner,
t.TableName

— work out sum of index usage for tables where index(s) have been used

SELECT TableName,
SumUsed =sum(Used)
into #sumused
from #used
where Used > 0
group by TableName
print “”
select TableName,
IndexName,
Selected,
Used,
WhenLastUsed
into #clean
from #used
where Used > 0
print “”
print ‘Tables accessed with Table scans and index usage as well’
print “”
SELECT
“TableName” = substring(t.Owner+”.”+t.TableName, 1, 30),
“Rows” = convert(numeric(10,0),s.RowTotal),
“Size/KB” = convert(numeric(10,0),s.Reserved),
“LogicalReads” = t.LogicalReads,
“PagesRead” = t.PagesRead,
“Table Scans” = str(t.Used, 8, 0),
“Index Usage” = str(u.SumUsed, 8, 0),
“IndexUsage/TableScan” = str(u.SumUsed*1.0/t.Used*1.0, 9, 2)
FROM
#tabscan t,
#table_size s,
#sumused u
WHERE
t.Owner = s.Owner
and t.TableName = s.TableName
and t.TableName = u.TableName
and s.TableName = u.TableName
and u.SumUsed > 0
ORDER BY
t.Owner,
t.TableName

SELECT TableName,
IndexName,
Selected,
Used,
“Selected_over_sum_selected” = convert(numeric(10,2),Selected*1.0/sum(Selected)*1.0),
“Used_over_sum_used” = convert(numeric(10,2),Used*1.0/sum(Used)*1.0),
“Used_over_selected” = convert(numeric(10,2),Used*1.0/Selected*1.0)
into #results
from #clean
group by TableName
if exists (select 1 from #results)
begin
print “”
print ‘Index usage analysis’
print “”
select
“TableName” = substring(i.Owner+”.”+i.TableName, 1, 30),
r.IndexName,
“IndexSize/KB” = i.reserved,
r.Selected,
r.Used,
–“Selected/SUM(Selected)” = r.Selected_over_sum_selected,
“Used/SUM(Used)” = convert(numeric(10,2),r.Used_over_sum_used)
–“Used/Selected” = r.Used_over_selected
from #results r,
#t1 i
where
r.TableName = i.TableName
and r.IndexName = i.IndexName
–and r.Used_over_sum_used < 1.0 order by r.TableName, r.Used_over_sum_used desc end end go grant exec on sp__montableusage to public go exit[/sql] sp__montableusage

Share Button

Leave a Reply

Your email address will not be published. Required fields are marked *

*
*

Facebook login by WP-FB-AutoConnect