Quantcast
Channel: Sybase – Jason L. Froebe – Tech tips and How Tos for Fellow Techies
Viewing all 102 articles
Browse latest View live

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

$
0
0

Back in 2006, Mich Talebzadeh createdSAP Sybase the sp__monusedtables stored procedure for reporting on table usage 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() function that was used to report on the estimated number of rows in favor of the row_count() function. I’ve updated the stored procedure to use the row_count() function.

diff sp__monusedtables.12 sp__monusedtables.15
14,18c14,19
< ------------------------------------------------------------------------------------------------
< -- Vers|  Date  |      Who           | DA | Description
< -------+--------+--------------------+----+-----------------------------------------------------
< -- 1.0 |07/04/06|  Mich Talebzadeh   |    | Reports on table usage via MDA tables
< -------+--------+--------------------+----+-----------------------------------------------------
---
> --------------------------------------------------------------------------------------------------
> -- Vers|   Date   |      Who           | DA | Description
> -------+----------+--------------------+----+-----------------------------------------------------
> -- 1.1 |11/18/2013|  Jason Froebe      |    | Update to use row_count
> -- 1.0 |07/04/2006|  Mich Talebzadeh   |    | Reports on table usage via MDA tables
> -------+----------+--------------------+----+-----------------------------------------------------
31a33
>              "DBID" = m.DBID,
64c66
< "Rows_in_table" = rowcnt(i.doampg)
---
>       "Rows_in_table" = row_count(t.DBID, o.id)
USE sybsystemprocs
go
IF EXISTS(SELECT 1 FROM sysobjects WHERE type = 'P' AND name = 'sp__monusedtables')
BEGIN
  DROP PROCEDURE sp__monusedtables
END
go
CREATE PROCEDURE sp__monusedtables
(
        @OWNER VARCHAR(30) = NULL,
   @OBJNAME VARCHAR(30) = NULL
)
AS
--------------------------------------------------------------------------------------------------
-- Vers|   Date   |      Who           | DA | Description
-------+----------+--------------------+----+-----------------------------------------------------
-- 1.1 |11/18/2013|  Jason Froebe      |    | Update to use row_count
-- 1.0 |07/04/2006|  Mich Talebzadeh   |    | Reports on table usage via MDA tables
-------+----------+--------------------+----+-----------------------------------------------------
BEGIN
   IF NOT EXISTS( SELECT 1
                    FROM sysobjects
                   WHERE type = 'U'
                     AND name = ISNULL(@OBJNAME, name)
                     AND USER_NAME(uid) = ISNULL(@OWNER, USER_NAME(uid)) )
   BEGIN
      PRINT "Table: %1!.%2! was not found", @OWNER, @OBJNAME
      RETURN -1
   END

  SELECT
                         "Owner" = ISNULL(@OWNER, USER_NAME(o.uid)),
                         "DBID" = m.DBID,
                         "TableName" = ISNULL(@OBJNAME, 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 user_name(o.uid) = ISNULL(@OWNER, user_name(o.uid))
       and o.name = ISNULL(@OBJNAME, 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
      "Owner" = user_name(o.uid),
      "TableName" =  o.name,
      "Rows_in_table" = row_count(t.DBID, o.id)
  INTO
      #tab1
  FROM
       sysobjects o,
       sysindexes i,
       master.dbo.spt_values d,
       #temp t
  WHERE
       user_name(o.uid) = t.Owner
       and o.name = t.TableName
       and o.type = 'U'
       and i.id = o.id
       and d.number = 1
       and d.type = 'E'

  SELECT
       Owner,
       TableName,
       "RowTotal" = sum(Rows_in_table)
  INTO
       #tab2
  FROM
       #tab1
  GROUP BY
       Owner,
       TableName

  PRINT ""
  PRINT "Displaying table statistics"
  PRINT ""
  SELECT
      --t.Owner,
      t.TableName,
      "Rows" = b.RowTotal,
                t.Inserted,
                t.Updated,
                t.Deleted,
      t.LogicalReads,
      t.LockRequests
  FROM
       #temp t,
       #tab2 b
  WHERE
       t.Owner = b.Owner
       and t.TableName = b.TableName
       --and t.WhenLastSelected is NOT NULL
       --and t.WhenLastUsed is NOT NULL
       --and t.LockRequests = 0
  ORDER BY
        t.Operations
END
go
GRANT ALL ON sp__monusedtables TO PUBLIC
go
exit

Ed Barlow Procedures: sp__groupprotect updated to show the group name properly for SAP Sybase ASE 15 and higher

$
0
0

Ed Barlow createdSAP Sybase the sp__groupprotect stored procedure for reporting group permissions in Sybase ASE as part of the excellent Extended Stored Procedures by Ed Barlow (AKA the Ed Barlow Stored Procedures).

The problem is that the group name is truncated often making it difficult to determine exactly which group a particular line applies to:

 type grp             tot    sel    upd    del    ins    rev    exe
 ---- --------------- ------ ------ ------ ------ ------ ------ ------
 D    application_gro 253    0      0      0      0      0      0
 D    dtm_tm_role     253    0      0      0      0      0      0
 D    ha_role         253    0      0      0      0      0      0
 D    webservices_rol 253    0      0      0      0      0      0

I’ve updated the stored procedure to show the entire group name:

 type grp                tot    sel    upd    del    ins    rev    exe
 ---- ------------------ ------ ------ ------ ------ ------ ------ ------
 D    application_group  253    0      0      0      0      0      0
 D    dtm_tm_role        253    0      0      0      0      0      0
 D    ha_role            253    0      0      0      0      0      0
 D    webservices_role   253    0      0      0      0      0      0
$ diff groupprotect.sql groupprotect.15
23c23
< create procedure sp__groupprotect( @dont_format char(1) = NULL )
---
> create procedure dbo.sp__groupprotect( @dont_format char(1) = NULL )
26a27,36
> --------------------------------------------------------------------------------------------------
> -- Vers|   Date   |      Who           | DA | Description
> -------+----------+--------------------+----+-----------------------------------------------------
> -- 1.1 |11/18/2013|  Jason Froebe      |    | Fix formatting
> -- 1.0 |          |  Edward M Barlow   |    | Stored procedure reporting group permissions
> -------+----------+--------------------+----+-----------------------------------------------------
>
> declare @max_name_size varchar(3)
> declare @exec_str varchar(2000)
>
110,112c120,125
< select type,grp=convert(char(15),group_name),tot=convert(char(6),total),sel=convert(char(6),s),upd=convert(char(6),u),del=convert(char(6),d),ins=convert(char(6),i),rev=convert(char(6),r),exe=convert(char(6),e)
<         from #objects
<         order by type,group_name
---
>         select @max_name_size = convert(varchar(3), max(char_length(group_name))) from #objects
>         select @exec_str =
>             'select type,grp=convert(char(' + @max_name_size + '),group_name),tot=convert(char(6),total),sel=convert(char(6),s),upd=convert(char(6),u),del=convert(char(6),d),ins=convert(char(6),i),rev=convert(char(6),r),exe=convert(char(6),e)
>             from #objects
>             order by type,group_name'
>         exec (@exec_str)

Here’s the full stored procedure code:

/* Procedure copyright(c) 1995 by Edward M Barlow */

/******************************************************************************
**
** Name        : sp__groupprotect.sql
**
**   permissions by object type / user group vs sel/upd/ins/del
**
******************************************************************************/
:r database
go
:r dumpdb
go

if exists (select * from sysobjects
           where  name = "sp__groupprotect"
           and    type = "P")
begin
   drop proc sp__groupprotect
end
go

create procedure dbo.sp__groupprotect( @dont_format char(1) = NULL )
as
set nocount on

--------------------------------------------------------------------------------------------------
-- Vers|   Date   |      Who           | DA | Description
-------+----------+--------------------+----+-----------------------------------------------------
-- 1.1 |11/18/2013|  Jason Froebe      |    | Fix formatting
-- 1.0 |          |  Edward M Barlow   |    | Stored procedure reporting group permissions
-------+----------+--------------------+----+-----------------------------------------------------

declare @max_name_size varchar(3)
declare @exec_str varchar(2000)

select distinct type,uid=sysusers.uid,group_name=sysusers.name,total=0,s=0,u=0,d=0,i=0,r=0,e=0
into   #objects
from   sysusers,   sysobjects
where  sysusers.uid=sysusers.gid
and    sysobjects.uid=1
and    ( sysusers.uid>=16390 or sysusers.uid < 16000 )

select distinct action,id,uid,protecttype,type="  "
into  #p
from  sysprotects p

update  #p
set     type=o.type
from    sysobjects o
where   o.id=#p.id
and     o.uid=1

update #objects set total=(select count(*) from sysobjects o
                                where o.type=n.type
                                and    o.uid=1)
from #objects n

update  #objects
set     s=(select count(*)
                from    #p
                where   #p.action=193
                and     #p.uid = #objects.uid
                and     #p.protecttype<=1
                and     #p.type = #objects.type
)
from #objects

update  #objects
set     u=(select count(*)
                from    #p
                where   #p.action=197
                and     #p.uid = #objects.uid
                and     #p.protecttype<=1
                and     #p.type = #objects.type
)
from #objects

update  #objects
set     d=(select count(*)
                from    #p
                where   #p.action=196
                and     #p.uid = #objects.uid
                and     #p.protecttype<=1
                and     #p.type = #objects.type
)
from #objects

update  #objects
set     i=(select count(*)
                from    #p
                where   #p.action=195
                and     #p.uid = #objects.uid
                and     #p.protecttype<=1
                and     #p.type = #objects.type
)
from #objects

update  #objects
set     r=(select count(*)
                from    #p
                where   #p.protecttype=2
                and     #p.uid = #objects.uid
                and     #p.type = #objects.type
)
from #objects

update  #objects
set     e=(select count(*)
                from    #p
                where   #p.action=224
                and     #p.uid = #objects.uid
                and     #p.protecttype<=1
                and     #p.type = #objects.type
)
from #objects

if @dont_format is null
begin
        select @max_name_size = convert(varchar(3), max(char_length(group_name))) from #objects
        select @exec_str =
            'select type,grp=convert(char(' + @max_name_size + '),group_name),tot=convert(char(6),total),sel=convert(char(6),s),upd=convert(char(6),u),del=convert(char(6),d),ins=convert(char(6),i),rev=convert(char(6),r),exe=convert(char(6),e)
            from #objects
            order by type,group_name'
        exec (@exec_str)
end
else
begin
        select type,grp=group_name,tot=convert(char(6),total),sel=convert(char(6),s),upd=convert(char(6),u),del=convert(char(6),d),ins=convert(char(6),i),rev=convert(char(6),r),exe=convert(char(6),e)
        from #objects
        order by type,group_name
end

return (0)
go
grant execute on sp__groupprotect to public
go

Ed Barlow Stored Procedures: sp__monunusedindex updated with formatting, including owner and all indexes for SAP Sybase ASE 15 and higher

$
0
0

Ed Barlow createdSAP Sybase the sp__monunusedindex stored procedure for displaying the indexes that have not been used since server start in Sybase ASE as part of the excellent Extended Stored Procedures by Ed Barlow (AKA the Ed Barlow Stored Procedures).

I’ve updated the stored procedure to include the table owner and all the indexes & index keys. I’ve also fixed the formatting of the data.

$ diff sp__monunusedindex.old sp__monunusedindex.15
21a22,27
> --------------------------------------------------------------------------------------------------
> -- Vers|   Date   |      Who           | DA | Description
> -------+----------+--------------------+----+-----------------------------------------------------
> -- 1.1 |11/20/2013|  Jason Froebe      |    | Show full index name and full index keys
> -- 1.0 |  2006    |  Edward Barlow     |    | show indexes that have not been used since server start
> -------+----------+--------------------+----+-----------------------------------------------------
23c29,34
< select Dbname=db_name(DBID),Object=object_name(ObjectID,DBID),IndexID,IndexName=i.name, ObjectID
---
>
> declare @max_ownername_size varchar(3)
> declare @max_keylist_size varchar(4)
> declare @exec_str varchar(2000)
>
> select Dbname=db_name(DBID), Object=object_name(ObjectID,DBID), IndexID, IndexName=i.name, ObjectID
27,39c38,45
< and   a.ObjectID=o.id  and DBID=db_id()
< and   o.id = i.id and a.IndexID=i.indid
< and   o.type='U'
< and       (LastOptSelectDate is null and OptSelectCount=0)
< -- and   RowsUpdated=0
< -- and   RowsDeleted=0
< -- and   PhysicalReads=0
< -- and   PhysicalWrites=0
< -- and   PagesRead=0
< and   object_name(ObjectID,DBID) not like 'sys%'
< and   object_name(ObjectID,DBID) not like 'rs_%'
< and    object_name(ObjectID,DBID) not like 'spt_%'
< and   IndexID!=0
---
>    and   a.ObjectID=o.id  and DBID=db_id()
>    and   o.id = i.id and a.IndexID=i.indid
>    and   o.type='U'
>    and       (LastOptSelectDate is null and OptSelectCount=0)
>    and   object_name(ObjectID,DBID) not like 'sys%'
>    and   object_name(ObjectID,DBID) not like 'rs_%'
>    and    object_name(ObjectID,DBID) not like 'spt_%'
>    and        IndexID!=0
42,45c48,51
< owner      char(30) not null,
<    uid        smallint not null,
<    name       char(30) not null,
<    index_name char(30) not null,
---
>    owner      sysname not null,
>    uid        int not null,
>    name       longsysname not null,
>    index_name longsysname not null,
53c59
< keylist    char(127) null,
---
>    keylist    varchar(2000) null,
58,73c64,79
< insert into   #indexlist
<    select owner      = user_name(o.uid),
<           o.uid,
<           name       = o.name,
<           index_name = i.name,
<           id = i.id,
<           indexid    = i.indid,
<           clust      = convert(char(1),null),
<           allow_dup  = convert(char(1),null),
<           ign_dup_key  = convert(char(1),null),
<           uniq       = convert(char(1),null),
<           suspect    = convert(char(1),null),
<           keylist    = convert(char(127),"N.A."),
<           status      = status, status2=i.status2
<    from   sysobjects o, sysindexes i, #tmp t
<    where  i.id   = o.id
---
> insert into   #indexlist
> select owner      = user_name(o.uid),
>    o.uid,
>    name       = o.name,
>    index_name = i.name,
>    id = i.id,
>    indexid    = i.indid,
>    clust      = convert(char(1),null),
>    allow_dup  = convert(char(1),null),
>    ign_dup_key  = convert(char(1),null),
>    uniq       = convert(char(1),null),
>    suspect    = convert(char(1),null),
>    keylist    = "N.A.",
>    status      = status, status2=i.status2
> from   sysobjects o, sysindexes i, #tmp t
> where  i.id   = o.id
75d80
< --and    o.type in ("U",@show_type)
106c111
< or     status2&8192= 8192
---
>    or status2 & 8192= 8192
111c116
< while ( @count < 17 )   /* 16 appears to be the max number of indexes */
---
> while ( @count < 250 )   /* max number of indexes = 250 */
113d117
<
120c124
<       set    keylist=rtrim(keylist)+","+index_col(name,indexid,@count,uid)
---
>       set    keylist = convert(varchar(2000), rtrim(keylist)+", "+index_col(name,indexid,@count,uid))
123c127,128
< if @@rowcount=0   break
---
>    if @@rowcount=0
>       break
132,138c137,143
< if @no_print is null
<         begin
<         print "   INDEX KEY:     c = clustered            u = unique"
<         print "                  a = allow dup row        s = suspect"
<         print "                  i = ignore dup key "
<         print ""
<               end
---
> if @no_print is null
> begin
>    print "   INDEX KEY:     c = clustered            u = unique"
>    print "                  a = allow dup row        s = suspect"
>    print "                  i = ignore dup key "
>    print ""
> end
140,146c145,173
< select "Name" = rtrim(name)+"."+index_name,
<        c   = isnull(clust,""),
<        u   = isnull(uniq,""),
<        i   = isnull(ign_dup_key,""),
<        a   = isnull(allow_dup,""),
<        s   = isnull(suspect,""),
<        "List of Index Keys"    = keylist
---
> if @dont_format is null
> begin
>    select @max_ownername_size = convert(varchar(3), isnull(max(char_length(owner)) + max(char_length(name)) + max(char_length(index_name)) + 2, 1) )
>       from #indexlist
>
>    select @max_keylist_size = convert(varchar(4), isnull(max(char_length(keylist)), 1) )
>       from #indexlist
>
>    select @exec_str =
>       'select "Name" = convert(varchar(' + @max_ownername_size + '), rtrim(owner) + "." + rtrim(name) + "." + index_name),
>          c   = isnull(clust,""),
>          u   = isnull(uniq,""),
>          i   = isnull(ign_dup_key,""),
>          a   = isnull(allow_dup,""),
>          s   = isnull(suspect,""),
>          "List of Index Keys"    = convert(varchar(' + @max_keylist_size + '), keylist)
>       from #indexlist
>       order by owner,name,indexid'
>    exec (@exec_str)
> end
> else
> begin
>    select "Name" = rtrim(owner) + "." + rtrim(name) + "." + index_name,
>       c   = isnull(clust,""),
>       u   = isnull(uniq,""),
>       i   = isnull(ign_dup_key,""),
>       a   = isnull(allow_dup,""),
>       s   = isnull(suspect,""),
>       "List of Index Keys"    = keylist
148a176
> end

full code of sp__monunusedindex:

use sybsystemprocs
go
/* Procedure copyright(c) 2006 by Edward M Barlow */

/******************************************************************************
**
** Name        : sp__monunusedindex
**
** Created By  : Ed Barlow
**
******************************************************************************/

IF EXISTS (SELECT * FROM sysobjects
           WHERE  name = "sp__monunusedindex"
           AND    type = "P")
   DROP PROC sp__monunusedindex

go

create proc sp__monunusedindex( @dont_format char(1) = null, @no_print char(1) = null)
as
--------------------------------------------------------------------------------------------------
-- Vers|   Date   |      Who           | DA | Description
-------+----------+--------------------+----+-----------------------------------------------------
-- 1.1 |11/20/2013|  Jason Froebe      |    | Show full index name and full index keys
-- 1.0 |  2006    |  Edward Barlow     |    | show indexes that have not been used since server start
-------+----------+--------------------+----+-----------------------------------------------------
begin

declare @max_ownername_size varchar(3)
declare @max_keylist_size varchar(4)
declare @exec_str varchar(2000)

select Dbname=db_name(DBID), Object=object_name(ObjectID,DBID), IndexID, IndexName=i.name, ObjectID
into #tmp
from master..monOpenObjectActivity a, sysobjects o, sysindexes i
where RowsInserted=0
   and   a.ObjectID=o.id  and DBID=db_id()
   and   o.id = i.id and a.IndexID=i.indid
   and   o.type='U'
   and       (LastOptSelectDate is null and OptSelectCount=0)
   and   object_name(ObjectID,DBID) not like 'sys%'
   and   object_name(ObjectID,DBID) not like 'rs_%'
   and    object_name(ObjectID,DBID) not like 'spt_%'
   and  IndexID!=0

create table #indexlist (
   owner      sysname not null,
   uid        int not null,
   name       longsysname not null,
   index_name longsysname not null,
   id         int not null,
   indexid    smallint not null,
   clust      char(1) null,
   allow_dup  char(1) null,
   ign_dup_key char(1) null,
   uniq       char(1) null,
   suspect    char(1) null,
   keylist    varchar(2000) null,
   status     smallint not null,
   status2     smallint not null
)

insert into   #indexlist
select owner      = user_name(o.uid),
   o.uid,
   name       = o.name,
   index_name = i.name,
   id = i.id,
   indexid    = i.indid,
   clust      = convert(char(1),null),
   allow_dup  = convert(char(1),null),
   ign_dup_key  = convert(char(1),null),
   uniq       = convert(char(1),null),
   suspect    = convert(char(1),null),
   keylist    = "N.A.",
   status      = status, status2=i.status2
from   sysobjects o, sysindexes i, #tmp t
where  i.id   = o.id
   and    i.id = ObjectID and i.indid=IndexID
   and      indid > 0

/* delete multiple rows */
delete #indexlist
from   #indexlist a, #indexlist b
where  a.indexid = 0
and    b.indexid != 0
and    a.name = b.name

update #indexlist
set    clust='Y'
where  indexid = 1
or                      status&16=16
or              status2&512 = 512

update #indexlist
set    uniq = 'Y'
where  status & 2 = 2

update #indexlist
set    ign_dup_key = 'Y'
where  status & 1 = 1

update #indexlist
set    allow_dup = 'Y'
where  status & 64 = 64

update #indexlist
set    suspect = 'Y'
where  status & 32768 = 32768
   or status2 & 8192= 8192

declare @count int
select  @count=1

while ( @count < 250 )   /* max number of indexes = 250 */
begin
   if @count=1
      update #indexlist
      set    keylist=index_col(name,indexid,1,uid)
      where  index_col(name,indexid,@count,uid) is not null
   else
      update #indexlist
      set    keylist = convert(varchar(2000), rtrim(keylist)+", "+index_col(name,indexid,@count,uid))
      where  index_col(name,indexid,@count,uid) is not null

   if @@rowcount=0
      break

   select @count=@count+1
end

update #indexlist
set    name=convert(char(30), rtrim(rtrim(substring(owner,1,15)) + "." +name))
where  owner!="dbo"

if @no_print is null
begin
   print "   INDEX KEY:     c = clustered            u = unique"
   print "                  a = allow dup row        s = suspect"
   print "                  i = ignore dup key "
   print ""
end

if @dont_format is null
begin
   select @max_ownername_size = convert(varchar(3), isnull(max(char_length(owner)) + max(char_length(name)) + max(char_length(index_name)) + 2, 1) )
      from #indexlist

   select @max_keylist_size = convert(varchar(4), isnull(max(char_length(keylist)), 1) )
      from #indexlist

   select @exec_str =
      'select "Name" = convert(varchar(' + @max_ownername_size + '), rtrim(owner) + "." + rtrim(name) + "." + index_name),
         c   = isnull(clust,""),
         u   = isnull(uniq,""),
         i   = isnull(ign_dup_key,""),
         a   = isnull(allow_dup,""),
         s   = isnull(suspect,""),
         "List of Index Keys"    = convert(varchar(' + @max_keylist_size + '), keylist)
      from #indexlist
      order by owner,name,indexid'
   exec (@exec_str)
end
else
begin
   select "Name" = rtrim(owner) + "." + rtrim(name) + "." + index_name,
      c   = isnull(clust,""),
      u   = isnull(uniq,""),
      i   = isnull(ign_dup_key,""),
      a   = isnull(allow_dup,""),
      s   = isnull(suspect,""),
      "List of Index Keys"    = keylist
   from #indexlist
   order by owner,name,indexid
end

end
go

Ed Barlow Stored Procedures: sp__monwaits updated with formatting for SAP Sybase ASE 15 and higher

$
0
0

Ed Barlow createdSAP Sybase the sp__monwaits stored procedure for displaying the wait times since server start in Sybase ASE as part of the excellent Extended Stored Procedures by Ed Barlow (AKA the Ed Barlow Stored Procedures).

The sp__monwaits often truncated the event description making it rather difficult to determine exactly which event occurred. I’ve expanded the size the field to reflect the length of the longest event description dynamically.

 Event                                    WaitTime    Waits
 ---------------------------------------- ----------- -----------
 xact coord: pause during idle loop           4001410       66688
 wait for buffer read to complete              532248    85475068
 wait for buffer write to complete              32235    15923057
 wait for buffer validation to complete          3680      162024
 wait for mass to stop changing                 30267    10315571
 wait for mass to finish changing               10774   502746724
 wait to acquire latch                          55839     7807761
 waiting for disk write to complete            115108    40656343
 waiting for disk write to complete             60530    11697654
 waiting for disk write to complete             27566     9398819
 waiting for disk write to complete             85976    50951106
 checkpoint process idle loop                  951594       16619
 hk: pause for some time                      2713933      530621
 wait for flusher to queue full DFLPIECE       151633      150265
 wait for data from client                       1933        6000
 wait until an engine has been offlined       1000427       33342
 wait for someone else to finish reading       372601    55500541
 waiting for semaphore                         391902    13636318
 waiting for CTLIB event to complete            87265   112396697
 waiting while allocating new client sock      997833       97155
 waiting while no network read or write i    11936037  1037354467
 waiting on run queue after yield              295191    72098512
 waiting on run queue after sleep              746636 -1313156962
 replication agent sleeping in retry slee        3839          64
 replication agent sleeping during flush      1840806    12733523
 waiting for incoming network data          201256524   265587239
 waiting for network send to complete         1175318   747115161
 waiting until last chance threshold is c        1144           3
 waiting for date or time in waitfor comm       68630         210

to

 Event                                              WaitTime    Waits
 -------------------------------------------------- ----------- -----------
 waiting for incoming network data                    221594153    12452930
 waiting for client connection request                  2760845      207231
 hk: pause for some time                                2754002      443443
 xact coord: pause during idle loop                      920462       15341
 wait until an engine has been offlined                  920462       30682
 Wait until heartbeat or check interval expires          920399        1534
 checkpoint process idle loop                            919400       18224
 replication agent sleeping during flush                 777679       91871
 replication agent sleeping in retry sleep               138301        2305
 wait for flusher to queue full DFLPIECE                  31029       31055
 waiting for regular buffer read to complete              11461    37289445
 waiting for last i/o on MASS to complete                  8079     2026180
 waiting on run queue after yield                          4914     4974455
 waiting on run queue after sleep                          3652    71141496
 wait for mass read to finish when getting page            3341     5365397
 wait for i/o to finish after writing last log page        2757     3624230
 waiting for network send to complete                      1404       58634
 waiting for buf write to complete before writing          1334     1452867

Differences:

$ diff sp__monwaits.old sp__monwaits.15
1,13d0
< <
< /*
< select distinct SPID,Id=substring(Login+"("+Application+")",1,30),SecondsWaiting=sum(SecondsWaiting),"Non Network Wait Reason"=c.Description
< from master..monProcess p,master..monWaitClassInfo c, master..monWaitEventInfo i
< where p.WaitEventID = i.WaitEventID
< and   i.WaitClassID = c.WaitClassID
< and   c.Description!="waiting for input from the network"
< group by c.WaitClassID,SPID
< order by SPID
< */
<
<
22d8
<
32a19,21
> declare @max_eventstr_size varchar(4)
> declare @exec_str varchar(2000)
>
34c23,25
< select "Event"=substring(i.Description,1,40),WaitTime,Waits
---
> begin
>       select "Event" = i.Description, WaitTime, Waits
>     into #tmp_nodelay
37a29,42
>
>     if @dont_format is null
>     begin
>         select @max_eventstr_size = convert(varchar(3), isnull(max(char_length(Event)), 1)) from #tmp_nodelay
>         select @exec_str = 'select "Event" = convert(varchar(' + @max_eventstr_size + '), Event), WaitTime, Waits from #tmp_nodelay order by WaitTime desc'
>         exec (@exec_str)
>     end
>     else
>     begin
>         select * from #tmp_nodelay order by WaitTime desc
>     end
>
>     delete #tmp_nodelay
> end
40c45
< select "Event"=substring(i.Description,1,40),WaitTime,Waits,s.WaitEventID
---
>       select "Event" = i.Description, WaitTime, Waits, s.WaitEventID
51a57
>
56,63c62
< select "Time"=convert(varchar(8),getdate(),8),
<                       "Event"=i.Event,
<                       WaitTime=s.WaitTime-i.WaitTime,
<                       Waits=s.Waits-i.Waits
<               from #tmp i, master..monSysWaits s
<               where (s.WaitTime>i.WaitTime or s.Waits>i.Waits)
< and s.WaitEventID= i.WaitEventID
<               order by WaitTime desc
---
>         select @max_eventstr_size = convert(varchar(3), isnull(max(char_length(Event)), 1)) from #tmp
64a64,73
>               select @exec_str = 'select "Time" = convert(varchar(8),getdate(),8),
>                          "Event" = convert(varchar(' + @max_eventstr_size + '), rtrim(i.Event)),
>                          WaitTime = s.WaitTime-i.WaitTime,
>                          Waits = s.Waits-i.Waits
>                  from #tmp i, master..monSysWaits s
>                  where (s.WaitTime > i.WaitTime or s.Waits > i.Waits)
>                  and s.WaitEventID= i.WaitEventID
>                  order by WaitTime desc'
>         exec (@exec_str)
>
68c77
< select "Event"=substring(i.Description,1,40),WaitTime,Waits,s.WaitEventID
---
>               select "Event"=i.Description, WaitTime, Waits, s.WaitEventID
70c79
< where s.WaitEventID= i.WaitEventID
---
>               where s.WaitEventID = i.WaitEventID

Full SQL text of sp__monwaits:

use sybsystemprocs
go
/* Procedure library copyright(c) 2004 by Edward M Barlow */

IF EXISTS (SELECT * FROM sysobjects
           WHERE  name = "sp__monwaits"
           AND    type = "P")
   DROP PROC sp__monwaits
go

CREATE PROC sp__monwaits(
                @num_sec_delay int=NULL,
                @num_iter int=NULL,
                @dont_format char(1)=NULL)
AS
set nocount on
declare @delay char(8)

declare @max_eventstr_size varchar(4)
declare @exec_str varchar(2000)

if @num_sec_delay is null
begin
        select "Event" = i.Description, WaitTime, Waits
    into #tmp_nodelay
        from master..monWaitEventInfo i, master..monSysWaits s
        where s.WaitEventID= i.WaitEventID
        and     WaitTime>1000

    if @dont_format is null
    begin
        select @max_eventstr_size = convert(varchar(3), isnull(max(char_length(Event)), 1)) from #tmp_nodelay
        select @exec_str = 'select "Event" = convert(varchar(' + @max_eventstr_size + '), Event), WaitTime, Waits from #tmp_nodelay order by WaitTime desc'
        exec (@exec_str)
    end
    else
    begin
        select * from #tmp_nodelay order by WaitTime desc
    end

    delete #tmp_nodelay
end
else
begin
        select "Event" = i.Description, WaitTime, Waits, s.WaitEventID
        into #tmp
        from master..monWaitEventInfo i, master..monSysWaits s
        where s.WaitEventID= i.WaitEventID

        if @num_sec_delay<10
                select @delay="00:00:0"+convert(char(1),@num_sec_delay)
        else
                select @delay="00:00:"+convert(char(2),@num_sec_delay)

        if @num_iter is null
                select @num_iter=100

        while @num_iter>0
        begin
                waitfor delay @delay

        select @max_eventstr_size = convert(varchar(3), isnull(max(char_length(Event)), 1)) from #tmp

                select @exec_str = 'select "Time" = convert(varchar(8),getdate(),8),
                           "Event" = convert(varchar(' + @max_eventstr_size + '), rtrim(i.Event)),
                           WaitTime = s.WaitTime-i.WaitTime,
                           Waits = s.Waits-i.Waits
                   from #tmp i, master..monSysWaits s
                   where (s.WaitTime > i.WaitTime or s.Waits > i.Waits)
                   and s.WaitEventID= i.WaitEventID
                   order by WaitTime desc'
        exec (@exec_str)

                delete #tmp

                insert #tmp
                select "Event"=i.Description, WaitTime, Waits, s.WaitEventID
                from master..monWaitEventInfo i, master..monSysWaits s
                where s.WaitEventID = i.WaitEventID

                select @num_iter = @num_iter - 1
        end
end

return

go

GRANT EXECUTE ON sp__monwaits  TO public
go

Ed Barlow Stored Procedures: sp__monrunning updated with formatting for SAP Sybase ASE 15 and higher

$
0
0

Mich Talebzadeh createdSAP Sybase the sp__monrunning stored procedure for displaying the procedures that are running for more than 100 ms as part of the excellent Extended Stored Procedures by Ed Barlow (AKA the Ed Barlow Stored Procedures).

I’ve cleaned up the format output and added the dont_format option:

$ diff sp__monrunning.old sp__monrunning.15
9c9,10
< create procedure sp__monrunning
---
> create procedure sp__monrunning(
>                      @dont_format char(1)=NULL)
11,16c12,18
< ------------------------------------------------------------------------------------------------
< -- Vers|  Date  |      Who           | DA | Description
< -------+--------+--------------------+----+-----------------------------------------------------
< -- 1.0 |07/04/06|  Mich Talebzadeh   |    | Statistics on processes currently being executed
< --     |        |                    |    | with Elapsed time > 100ms
< -------+--------+--------------------+----+-----------------------------------------------------
---
> --------------------------------------------------------------------------------------------------
> -- Vers|   Date   |      Who           | DA | Description
> -------+----------+--------------------+----+-----------------------------------------------------
> -- 1.1 |11/20/2013|  Jason Froebe      |    | Cleaned up the report format, added dont_format option
> -- 1.0 |07/04/2006|  Mich Talebzadeh   |    | Statistics on processes currently being executed
> --     |          |                    |    | with Elapsed time > 100ms
> -------+--  ------+--------------------+----+-----------------------------------------------------
18,22c20,24
< declare @time datetime
<       select @time = getdate()
<       --print ""
<       --print "Stats for various procedures at %1!. Server up since %2!", @time, @@boottime
<       --print ""
---
>     declare @max_loginname_size varchar(3)
>     declare @max_procname_size varchar(3)
>     declare @max_dbname_size varchar(3)
>     declare @exec_str varchar(2000)
>
35c37
< "Name" = substring(suser_name(p.suid),1,20),
---
>               "Name" = suser_name(p.suid),
37,39c39,42
< "Procedure" = ProcName,
<               "Database" = DBNAME,
<               "Elapsed Time/ms" = TimeMs
---
>               ProcName,
>               DBNAME,
>               TimeMs
>     into #proc_report
43c46,75
< order by TimeMs asc
---
>
>     select @max_loginname_size = convert(varchar(3), isnull( max(char_length(Name)), 1)),
>         @max_procname_size = convert(varchar(3), isnull( max(char_length(ProcName)), 1)),
>         @max_dbname_size = convert(varchar(3), isnull( max(char_length(DBNAME)), 1))
>     from #proc_report
>
>     if @dont_format is null
>     begin
>         select @exec_str = 'select
>             "Name" = convert(varchar(' + @max_loginname_size + '), Name),
>                   SPID,
>                   "Procedure" = convert(varchar(' + @max_procname_size + '), ProcName),
>                   "Database" = convert(varchar(' + @max_dbname_size + '), DBNAME),
>                   "Elapsed Time/ms" = TimeMs
>         from #proc_report
>           order by TimeMs asc'
>
>         exec (@exec_str)
>     end
>     else
>     begin
>         select
>             "Name" = Name,
>                   SPID,
>                   "Procedure" = ProcName,
>                   "Database" = DBNAME,
>                   "Elapsed Time/ms" = TimeMs
>         from #proc_report
>           order by TimeMs asc
>     end

Full SQL code of sp__monrunning:

use sybsystemprocs
go

IF EXISTS (SELECT * FROM sysobjects
           WHERE  name = "sp__monrunning"
           AND    type = "P")
   DROP PROC sp__monrunning
go
create procedure sp__monrunning(
                     @dont_format char(1)=NULL)
as
--------------------------------------------------------------------------------------------------
-- Vers|   Date   |      Who           | DA | Description
-------+----------+--------------------+----+-----------------------------------------------------
-- 1.1 |11/20/2013|  Jason Froebe      |    | Cleaned up the report format, added dont_format option
-- 1.0 |07/04/2006|  Mich Talebzadeh   |    | Statistics on processes currently being executed
--     |          |                    |    | with Elapsed time > 100ms
-------+--  ------+--------------------+----+-----------------------------------------------------
begin
    declare @max_loginname_size varchar(3)
    declare @max_procname_size varchar(3)
    declare @max_dbname_size varchar(3)
    declare @exec_str varchar(2000)

        select
                SPID,
                ProcName = isnull(object_name(ProcedureID, DBID),"UNKNOWN"),
                DBNAME = isnull(db_name(DBID), "UNKNOWN"),
                TimeMs = datediff(ms, min(StartTime), max(EndTime))
                into #performance
                from master..monSysStatement m
        where db_name(DBID) != 'sybsystemprocs'
        group by SPID, DBID, ProcedureID, BatchID
        having ProcedureID != 0

        select distinct
                "Name" = suser_name(p.suid),
                SPID,
                ProcName,
                DBNAME,
                TimeMs
    into #proc_report
        from #performance t, master..sysprocesses p
        where t.SPID = p.spid
        and TimeMs >= 100

    select @max_loginname_size = convert(varchar(3), isnull( max(char_length(Name)), 1)),
        @max_procname_size = convert(varchar(3), isnull( max(char_length(ProcName)), 1)),
        @max_dbname_size = convert(varchar(3), isnull( max(char_length(DBNAME)), 1))
    from #proc_report

    if @dont_format is null
    begin
        select @exec_str = 'select
            "Name" = convert(varchar(' + @max_loginname_size + '), Name),
                    SPID,
                    "Procedure" = convert(varchar(' + @max_procname_size + '), ProcName),
                    "Database" = convert(varchar(' + @max_dbname_size + '), DBNAME),
                    "Elapsed Time/ms" = TimeMs
        from #proc_report
            order by TimeMs asc'

        exec (@exec_str)
    end
    else
    begin
        select
            "Name" = Name,
                    SPID,
                    "Procedure" = ProcName,
                    "Database" = DBNAME,
                    "Elapsed Time/ms" = TimeMs
        from #proc_report
            order by TimeMs asc
    end
end
go
grant exec on sp__monrunning to public
go
exit

Ed Barlow Stored Procedures: sp__monobj Updated with formatting for SAP Sybase ASE 15 and higher

$
0
0

Ed Barlow createdSAP Sybase the sp__monobj uses a heuristic algorithm to find which objects are most busy as part of the excellent Extended Stored Procedures by Ed Barlow (AKA the Ed Barlow Stored Procedures).

I’ve cleaned up the format output

Differences:

diff sp__monobj.old sp__monobj.15
17a18,26
> --------------------------------------------------------------------------------------------------
> -- Vers|   Date   |      Who           | DA | Description
> -------+----------+--------------------+----+-----------------------------------------------------
> -- 1.1 |11/20/2013|  Jason Froebe      |    | Fix formatting of outputs
> -- 1.0 |  2006    |  Edward Barlow     |    | Shows Highest Usage Objects Based On Mda tables.
> --     |          |                    |    |  This uses a heuristic algorithm to find what objects
> --     |          |                    |    |  are most busy.
> -------+----------+--------------------+----+-----------------------------------------------------
>
21a31,34
> declare @max_objectname_size varchar(3)
> declare @exec_str varchar(2000)
>
>
34a48,51
>     print ""
>     print "    score = LogicalReads/100 + PhysicalReads/10 + PhysicalWrites + RowsInserted + RowsDeleted + RowsUpdated + LockRequests + Lockwaits"
>     print ""
>
36,37c53,55
< select ObjName=convert(varchar(40),db_name(DBID)+"."+object_name(ObjectID,DBID)),
<       score= LogicalReads/100 +
---
>
>       select ObjName = db_name(DBID) + ".." + object_name(ObjectID, DBID),
>       score = LogicalReads/100        +
45,46c63,65
< from    master..monOpenObjectActivity
<       where   IndexID=0
---
>     into #busy_report
>       from master..monOpenObjectActivity
>       where IndexID=0
55c74
< and     db_name(DBID)!="tempdb"
---
>       and     DBName !="tempdb"
57a77
>
58a79,87
>
>     select @max_objectname_size = convert(varchar(3), isnull( max(char_length(ObjName)), 1)) from #busy_report
>
>     select @exec_str = 'select "Object Name" = convert(varchar(' + @max_objectname_size + '), ObjName), score
>         from #busy_report
>         order by score desc'
>
>     exec (@exec_str)
>
72a102,121
>     create table #busy_report_iter_obj (
>         ObjName varchar(255) not null,
>         Op bigint not null,
>         LogReads int not null,
>         PhysReads int not null,
>         PageReads int not null,
>         Writes int not null,
>         Ins int not null,
>         Del int not null,
>         Upd int not null,
>         Locks int not null,
>         LockWt int not null)
>
>     create table #busy_report_iter (
>         ObjName varchar(255) not null,
>         Op int not null,
>         Reads int not null,
>         Writes int not null,
>         NumRows bigint not null)
>
81,86c130,131
< -- select *
<                       -- from master..monOpenObjectActivity
<                       -- where IndexID=0 and db_name(DBID)!='tempdb'
<                       -- and ( @object_name is null or @object_name=object_name(ObjectID, DBID))
<
<               select distinct ObjName=convert(varchar(39),db_name(o.DBID)+"."+object_name(o.ObjectID,o.DBID)),
---
>             insert into #busy_report_iter_obj
>                   select distinct ObjName = db_name(o.DBID) + ".." + object_name(o.ObjectID,o.DBID),
88c133
< LogReads=o.LogicalReads - i.LogicalReads,
---
>                           LogReads=o.LogicalReads - i.LogicalReads,
92,103c137,167
< "Ins"=o.RowsInserted -i.RowsInserted,
<                               "Del"= o.RowsDeleted  - i.RowsDeleted,
<                               "Upd"= o.RowsUpdated - i.RowsUpdated ,
<                               "Locks"= o.LockRequests - i.LockRequests,
<                               "LockWt"= o.LockWaits - i.LockWaits
<               from  master..monOpenObjectActivity o,#tmp i
<               where o.IndexID=i.IndexID
<                       and o.ObjectID=i.ObjectID
<                       and o.DBID=i.DBID
<                       and o.IndexID=i.IndexID
<                       and o.IndexID=0
<                       and i.IndexID=0
---
>                           Ins=o.RowsInserted -i.RowsInserted,
>                               Del= o.RowsDeleted  - i.RowsDeleted,
>                               Upd= o.RowsUpdated - i.RowsUpdated ,
>                               Locks= o.LockRequests - i.LockRequests,
>                               LockWt= o.LockWaits - i.LockWaits
>                   from  master..monOpenObjectActivity o,#tmp i
>                   where o.IndexID=i.IndexID
>                           and o.ObjectID=i.ObjectID
>                           and o.DBID=i.DBID
>                           and o.IndexID=i.IndexID
>                           and o.IndexID=0
>                           and i.IndexID=0
>
>             select @max_objectname_size = convert(varchar(3), isnull( max(char_length(ObjName)), 1)) from #busy_report_iter_obj
>
>             select @exec_str = 'select "Object Name" = convert(varchar(' + @max_objectname_size + '), ObjName),
>                               Op,
>                           LogReads,
>                               PhysReads,
>                               PageReads,
>                               Writes,
>                           Ins,
>                               Del,
>                               Upd,
>                               Locks,
>                               LockWt
>                 from #busy_report_iter_obj'
>
>             exec (@exec_str)
>
>             delete #busy_report_iter_obj
107c171
< set rowcount 10
---
>                   set rowcount 10
109,138c173,202
< select distinct ObjName=convert(varchar(39),db_name(o.DBID)+"."+object_name(o.ObjectID,o.DBID)),
<               Op=o.Operations-i.Operations,
<       Reads=o.LogicalReads+ o.PhysicalReads- i.LogicalReads- i.PhysicalReads,
<               Writes=o.PhysicalWrites-i.PhysicalWrites,
<       "Rows"=o.RowsInserted + o.RowsDeleted   + o.RowsUpdated-i.RowsInserted - i.RowsDeleted - i.RowsUpdated
<       from  master..monOpenObjectActivity o,#tmp i
<    where    o.IndexID=i.IndexID
<               and o.ObjectID=i.ObjectID
<               and o.DBID=i.DBID
<               and o.IndexID=i.IndexID
<               and o.IndexID=0
<               and i.IndexID=0
<               -- and ( o.LogicalReads>0 or o.LockRequests>0 )
< order by
<       o.LogicalReads/100      +
<       o.PhysicalReads/10      +
<       o.PhysicalWrites                +
<       o.RowsInserted                  +
<       o.RowsDeleted                   +
<       o.RowsUpdated                   +
<       o.LockRequests/100   +
<       o.LockWaits             -
<       i.LogicalReads/100      -
<       i.PhysicalReads/10      -
<       i.PhysicalWrites                -
<       i.RowsInserted                  -
<       i.RowsDeleted                   -
<       i.RowsUpdated                   -
<       i.LockRequests/100   -
<       i.LockWaits    desc
---
>             insert into #busy_report_iter
>             select distinct ObjName = db_name(o.DBID) + ".." + object_name(o.ObjectID,o.DBID),
>                       Op = o.Operations-i.Operations,
>                 Reads = o.LogicalReads+ o.PhysicalReads- i.LogicalReads- i.PhysicalReads,
>                       Writes = o.PhysicalWrites-i.PhysicalWrites,
>                 NumRows = o.RowsInserted + o.RowsDeleted   + o.RowsUpdated-i.RowsInserted - i.RowsDeleted - i.RowsUpdated
>             from  master..monOpenObjectActivity o,#tmp i
>             where    o.IndexID=i.IndexID
>                       and o.ObjectID=i.ObjectID
>                       and o.DBID=i.DBID
>                       and o.IndexID=i.IndexID
>                       and o.IndexID=0
>                       and i.IndexID=0
>             order by
>                   o.LogicalReads/100  +
>                 o.PhysicalReads/10    +
>                 o.PhysicalWrites              +
>                 o.RowsInserted                +
>                 o.RowsDeleted                 +
>                 o.RowsUpdated                 +
>                 o.LockRequests/100   +
>                 o.LockWaits                   -
>                   i.LogicalReads/100  -
>                 i.PhysicalReads/10    -
>                 i.PhysicalWrites              -
>                 i.RowsInserted                -
>                 i.RowsDeleted                 -
>                 i.RowsUpdated                 -
>                 i.LockRequests/100   -
>                 i.LockWaits    desc
139a204,215
>             select @max_objectname_size = convert(varchar(3), isnull( max(char_length(ObjName)), 1)) from #busy_report_iter
>
>             select @exec_str = 'select "Object Name" = convert(varchar(' + @max_objectname_size + '), ObjName),
>                 Op,
>                 Reads,
>                 Writes,
>                 NumRows
>             from #busy_report_iter'
>
>             exec (@exec_str)
>
>             delete #busy_report_iter
152d227
< -- select 1,* from #tmp where object_id('sp_aux_getsize')=ObjectID and DBID=db_id('master')

SQL of sp__monobj:

use sybsystemprocs
go
/* Procedure library copyright(c) 2004-2006 by Edward M Barlow */

IF EXISTS (SELECT * FROM sysobjects
           WHERE  name = "sp__monobj"
           AND    type = "P")
   DROP PROC sp__monobj

go

CREATE PROC sp__monobj(
                @num_sec_delay int=NULL,
                @num_iter int=NULL,
                @dont_format char(1)=NULL,
                @object_name varchar(30)=NULL)
AS
--------------------------------------------------------------------------------------------------
-- Vers|   Date   |      Who           | DA | Description
-------+----------+--------------------+----+-----------------------------------------------------
-- 1.1 |11/20/2013|  Jason Froebe      |    | Fix formatting of outputs
-- 1.0 |  2006    |  Edward Barlow     |    | Shows Highest Usage Objects Based On Mda tables.
--     |          |                    |    |  This uses a heuristic algorithm to find what objects
--     |          |                    |    |  are most busy.
-------+----------+--------------------+----+-----------------------------------------------------

set nocount on
declare @delay char(8)
declare @objid int

declare @max_objectname_size varchar(3)
declare @exec_str varchar(2000)


if @object_name is not null
begin
        select @objid=ObjectID
        from master..monOpenObjectActivity where object_name(ObjectID,DBID)=@object_name
        if @objid is null
                return
end


if @num_sec_delay is null
begin
        --Busy Object Report
        print "Top 20 Used Objects"
    print ""
    print "    score = LogicalReads/100 + PhysicalReads/10 + PhysicalWrites + RowsInserted + RowsDeleted + RowsUpdated + LockRequests + Lockwaits"
    print ""

        set rowcount 20

        select ObjName = db_name(DBID) + ".." + object_name(ObjectID, DBID),
        score = LogicalReads/100        +
                PhysicalReads/10 +
                PhysicalWrites +
                RowsInserted   +
                RowsDeleted    +
                RowsUpdated    +
                LockRequests   +
                LockWaits
    into #busy_report
        from master..monOpenObjectActivity
        where IndexID=0
        and LogicalReads/100    +
                PhysicalReads/10 +
                PhysicalWrites +
                RowsInserted   +
                RowsDeleted    +
                RowsUpdated    +
                LockRequests   +
                LockWaits      >1000
        and     DBName !="tempdb"
        and ( @object_name is null or @object_name=object_name(ObjectID, DBID))
        order by score desc

        set rowcount 0

    select @max_objectname_size = convert(varchar(3), isnull( max(char_length(ObjName)), 1)) from #busy_report

    select @exec_str = 'select "Object Name" = convert(varchar(' + @max_objectname_size + '), ObjName), score
        from #busy_report
        order by score desc'

    exec (@exec_str)

end
else
begin
        select *
        into #tmp
        from master..monOpenObjectActivity
        where IndexID=0 and db_name(DBID)!='tempdb'
        and ( @object_name is null or ObjectID=@objid )

        if @num_sec_delay<10
                select @delay="00:00:0"+convert(char(1),@num_sec_delay)
        else
                select @delay="00:00:"+convert(char(2),@num_sec_delay)

    create table #busy_report_iter_obj (
        ObjName varchar(255) not null,
        Op bigint not null,
        LogReads int not null,
        PhysReads int not null,
        PageReads int not null,
        Writes int not null,
        Ins int not null,
        Del int not null,
        Upd int not null,
        Locks int not null,
        LockWt int not null)

    create table #busy_report_iter (
        ObjName varchar(255) not null,
        Op int not null,
        Reads int not null,
        Writes int not null,
        NumRows bigint not null)

        if @num_iter is null
                select @num_iter=100
        while @num_iter>0
        begin
                waitfor delay @delay

                if( @object_name is not null )
                begin
            insert into #busy_report_iter_obj
                    select distinct ObjName = db_name(o.DBID) + ".." + object_name(o.ObjectID,o.DBID),
                                Op=o.Operations-i.Operations,
                    LogReads=o.LogicalReads - i.LogicalReads,
                                PhysReads=o.PhysicalReads- i.PhysicalReads,
                                PageReads=o.PagesRead- i.PagesRead,
                                Writes=o.PhysicalWrites-i.PhysicalWrites,
                    Ins=o.RowsInserted -i.RowsInserted,
                                Del= o.RowsDeleted  - i.RowsDeleted,
                                Upd= o.RowsUpdated - i.RowsUpdated ,
                                Locks= o.LockRequests - i.LockRequests,
                                LockWt= o.LockWaits - i.LockWaits
            from  master..monOpenObjectActivity o,#tmp i
                    where o.IndexID=i.IndexID
                            and o.ObjectID=i.ObjectID
                            and o.DBID=i.DBID
                            and o.IndexID=i.IndexID
                            and o.IndexID=0
                            and i.IndexID=0

            select @max_objectname_size = convert(varchar(3), isnull( max(char_length(ObjName)), 1)) from #busy_report_iter_obj

            select @exec_str = 'select "Object Name" = convert(varchar(' + @max_objectname_size + '), ObjName),
                                Op,
                    LogReads,
                                PhysReads,
                                PageReads,
                                Writes,
                    Ins,
                                Del,
                                Upd,
                                Locks,
                                LockWt
                from #busy_report_iter_obj'

            exec (@exec_str)

            delete #busy_report_iter_obj
                end
                else
                begin
                    set rowcount 10

            insert into #busy_report_iter
            select distinct ObjName = db_name(o.DBID) + ".." + object_name(o.ObjectID,o.DBID),
                        Op = o.Operations-i.Operations,
                Reads = o.LogicalReads+ o.PhysicalReads- i.LogicalReads- i.PhysicalReads,
                        Writes = o.PhysicalWrites-i.PhysicalWrites,
                NumRows = o.RowsInserted + o.RowsDeleted   + o.RowsUpdated-i.RowsInserted - i.RowsDeleted - i.RowsUpdated
            from  master..monOpenObjectActivity o,#tmp i
            where    o.IndexID=i.IndexID
                        and o.ObjectID=i.ObjectID
                        and o.DBID=i.DBID
                        and o.IndexID=i.IndexID
                        and o.IndexID=0
                        and i.IndexID=0
            order by
                    o.LogicalReads/100  +
                o.PhysicalReads/10      +
                o.PhysicalWrites                +
                o.RowsInserted                  +
                o.RowsDeleted                   +
                o.RowsUpdated                   +
                o.LockRequests/100   +
                o.LockWaits             -
                    i.LogicalReads/100  -
                i.PhysicalReads/10      -
                i.PhysicalWrites                -
                i.RowsInserted                  -
                i.RowsDeleted                   -
                i.RowsUpdated                   -
                i.LockRequests/100   -
                i.LockWaits    desc

            select @max_objectname_size = convert(varchar(3), isnull( max(char_length(ObjName)), 1)) from #busy_report_iter

            select @exec_str = 'select "Object Name" = convert(varchar(' + @max_objectname_size + '), ObjName),
                Op,
                Reads,
                Writes,
                NumRows
            from #busy_report_iter'

            exec (@exec_str)

            delete #busy_report_iter
                set rowcount 0

                end

                delete #tmp

                insert #tmp
                select *
                from master..monOpenObjectActivity
                where IndexID=0 and db_name(DBID)!='tempdb'
                and ( @object_name is null or ObjectID=@objid )

                select @num_iter = @num_iter - 1
        end
end

return

go

GRANT EXECUTE ON sp__monobj  TO public
go

HOWTO: Building Perl Module DBD::Sybase 1.15 for ActiveState Perl (Windows 32bit) 5.16.3 using the MinGW compiler

$
0
0

We no longer are tied to using Microsoft’s SAP SybaseVisual C++ compiler for building Michael Peppler’s Perl Module DBD::Sybase 1.15 for ActiveState Perl (Windows 32bit)!

We need to make a few changes to SAP Sybase’s Openclient though. Don’t worry, the changes are only needed to build the module. I used Sybase Openclient 15.7 ESD 7 but you should be able to use any 15.7 version of Openclient with minimal changes.

%SYBASE%\%SYBASE_OCS%\include\csconfig.h differences:

$ diff csconfig.h.old csconfig.h
58a59,63
> /* Load MinGW specific definitions */
> #if defined(__MINGW32__)
> #include "_mingw.h"
> #endif /* __MINGW32__ */
>
74c79
< #if ((SYB_MSC_VER >= 800)  || defined(__BORLANDC__))
---
> #if ((SYB_MSC_VER >= 800)  || defined(__BORLANDC__)) || defined(__MINGW32__)
84c89
< #else /* ((SYB_MSC_VER >= 800) || defined(__BORLANDC__)) */
---
> #else /* ((SYB_MSC_VER >= 800) || defined(__BORLANDC__)) || defined(__MINGW32__) */
94c99
< #endif /* ((SYB_MSC_VER >= 800) || defined(__BORLANDC__)) */
---
> #endif /* ((SYB_MSC_VER >= 800) || defined(__BORLANDC__)) || defined(__MINGW32__) */

%SYBASE%\%SYBASE_OCS%\include\sybfront.h differences:

$ diff sybfront.h.old sybfront.h
162c162
< #if !defined(_MSC_VER) && !defined(__BORLANDC__)
---
> #if !defined(_MSC_VER) && !defined(__BORLANDC__) && !defined(__MINGW32__)
180c180
< #if !defined(_MSC_VER) && !defined(__BORLANDC__)
---
> #if !defined(_MSC_VER) && !defined(__BORLANDC__) && !defined(__MINGW32__)

csconfig
sybfront

We now need to copy the *.lib files in %SYBASE%\%SYBASE_OCS%\lib appending “.a” in place of the “.lib” suffix:
libs

Don’t you perlthink SAP Sybase should add the changes above to OpenClient? I think so. Let your SAP Representative know!

Now we’re ready to build the module!

U:\build\DBD-Sybase-1.15>perl Makefile.PL
Set up gcc environment - 3.4.5 (mingw-vista special r3)
Sybase OpenClient 15.7 found.

By default DBD::Sybase 1.05 and later use the 'CHAINED' mode (where available)
when 'AutoCommit' is turned off. Versions 1.04 and older instead managed
the transactions explicitly with a 'BEGIN TRAN' before the first DML
statement. Using the 'CHAINED' mode is preferable as it is the way that
Sybase implements AutoCommit handling for both its ODBC and JDBC drivers.

Use 'CHAINED' mode by default (Y/N) [Y]:

The DBD::Sybase module need access to a Sybase server to run the tests.
To clear an entry please enter 'undef'
Sybase server to use (default: SYBASE): test_svr
User ID to log in to Sybase (default: sa):
Password (default: undef):
Sybase database to use on sd02 (default: undef): tempdb

* Writing login information, including password, to file PWD.

Checking if your kit is complete...
Looks good
Warning (mostly harmless): No library found for -llibsybtcl.lib
Warning (mostly harmless): No library found for -llibsybcomn.lib
Warning (mostly harmless): No library found for -llibsybintl.lib
Multiple copies of Driver.xst found in: C:/Perl/site/lib/auto/DBI/ C:/Perl/lib/auto/DBI/ at Makefile.PL line 80.
Using DBI 1.63 (for perl 5.016003 on MSWin32-x86-multi-thread) installed in C:/Perl/site/lib/auto/DBI/
Generating a dmake-style Makefile
Writing Makefile for DBD::Sybase
Writing MYMETA.yml and MYMETA.json

So far so good, so let’s continue with compiling and building the module:

U:\build\DBD-Sybase-1.15>dmake
dmake.exe:  makefile:  line 454:  Warning: -- Macro `BOOTSTRAP' redefined after use
cp dbd-sybase.pod blib\lib\DBD\dbd-sybase.pod
cp Sybase.pm blib\lib\DBD\Sybase.pm
C:\Perl\bin\perl.exe -p -e "s/~DRIVER~/Sybase/g" C:\Perl\site\lib\auto\DBI\Driver.xst > Sybase.xsi
C:\Perl\bin\perl.exe C:\Perl\site\lib\ExtUtils\xsubpp  -typemap C:\Perl\lib\ExtUtils\typemap  Sybase.xs > Sybase.xsc && C:\Perl\bin\perl.exe -MExtUtil
s::Command -e mv -- Sybase.xsc Sybase.c
C:\Perl\site\bin\gcc.exe -c  -IC:\Sybase/OCS-15_0/include -IC:/Perl/site/lib/auto/DBI   -DNDEBUG -DWIN32 -D_CONSOLE -DNO_STRICT -DPERL_TEXTMODE_SCRIPT
S -DUSE_SITECUSTOMIZE -DPERL_IMPLICIT_CONTEXT -DPERL_IMPLICIT_SYS -DUSE_PERLIO -D_USE_32BIT_TIME_T -DHASATTRIBUTE -fno-strict-aliasing -mms-bitfields
-O2       -DVERSION=\"1.15\"    -DXS_VERSION=\"1.15\"  "-IC:\Perl\lib\CORE"   Sybase.c
C:\Perl\site\bin\gcc.exe -c  -IC:\Sybase/OCS-15_0/include -IC:/Perl/site/lib/auto/DBI   -DNDEBUG -DWIN32 -D_CONSOLE -DNO_STRICT -DPERL_TEXTMODE_SCRIPT
S -DUSE_SITECUSTOMIZE -DPERL_IMPLICIT_CONTEXT -DPERL_IMPLICIT_SYS -DUSE_PERLIO -D_USE_32BIT_TIME_T -DHASATTRIBUTE -fno-strict-aliasing -mms-bitfields
-O2       -DVERSION=\"1.15\"    -DXS_VERSION=\"1.15\"  "-IC:\Perl\lib\CORE"   dbdimp.c
dbdimp.c: In function `syb_st_execute':
dbdimp.c:3906: warning: passing arg 2 of `ct_results' from incompatible pointer type
dbdimp.c:3930: warning: passing arg 5 of `ct_bind' from incompatible pointer type
Running Mkbootstrap for DBD::Sybase ()
C:\Perl\bin\perl.exe -MExtUtils::Command -e chmod -- 644 Sybase.bs
C:\Perl\bin\perl.exe -MExtUtils::Mksymlists \
     -e "Mksymlists('NAME'=>\"DBD::Sybase\", 'DLBASE' => 'Sybase', 'DL_FUNCS' => {  }, 'FUNCLIST' => [], 'IMPORTS' => {  }, 'DL_VARS' => []);"
Set up gcc environment - 3.4.5 (mingw-vista special r3)
C:\Perl\site\bin\dlltool.exe --def Sybase.def --output-exp dll.exp
C:\Perl\site\bin\g++.exe -o blib\arch\auto\DBD\Sybase\Sybase.dll -Wl,--base-file -Wl,dll.base -LC:\Sybase/OCS-15_0/lib -mdll -L"C:\Perl\lib\CORE" Syba
se.o    dbdimp.o   C:\Perl\lib\CORE\perl516.lib C:\Sybase\OCS-15_0\lib\libsybct.lib C:\Sybase\OCS-15_0\lib\libsybcs.lib C:\Sybase\OCS-15_0\lib\libsybb
lk.lib C:\Perl\site\lib\auto\MinGW\lib\libm.a C:\Perl\site\lib\auto\MinGW\lib\libkernel32.a C:\Perl\site\lib\auto\MinGW\lib\libuser32.a C:\Perl\site\l
ib\auto\MinGW\lib\libgdi32.a C:\Perl\site\lib\auto\MinGW\lib\libwinspool.a C:\Perl\site\lib\auto\MinGW\lib\libcomdlg32.a C:\Perl\site\lib\auto\MinGW\l
ib\libadvapi32.a C:\Perl\site\lib\auto\MinGW\lib\libshell32.a C:\Perl\site\lib\auto\MinGW\lib\libole32.a C:\Perl\site\lib\auto\MinGW\lib\liboleaut32.a
 C:\Perl\site\lib\auto\MinGW\lib\libnetapi32.a C:\Perl\site\lib\auto\MinGW\lib\libuuid.a C:\Perl\site\lib\auto\MinGW\lib\libws2_32.a C:\Perl\site\lib\
auto\MinGW\lib\libmpr.a C:\Perl\site\lib\auto\MinGW\lib\libwinmm.a C:\Perl\site\lib\auto\MinGW\lib\libversion.a C:\Perl\site\lib\auto\MinGW\lib\libodb
c32.a C:\Perl\site\lib\auto\MinGW\lib\libodbccp32.a C:\Perl\site\lib\auto\MinGW\lib\libcomctl32.a C:\Perl\site\lib\auto\MinGW\lib\libmsvcrt.a dll.exp
C:\Perl\site\bin\dlltool.exe --def Sybase.def --base-file dll.base --output-exp dll.exp
C:\Perl\site\bin\g++.exe -o blib\arch\auto\DBD\Sybase\Sybase.dll -LC:\Sybase/OCS-15_0/lib -mdll -L"C:\Perl\lib\CORE" Sybase.o   dbdimp.o   C:\Perl\lib
\CORE\perl516.lib C:\Sybase\OCS-15_0\lib\libsybct.lib C:\Sybase\OCS-15_0\lib\libsybcs.lib C:\Sybase\OCS-15_0\lib\libsybblk.lib C:\Perl\site\lib\auto\M
inGW\lib\libm.a C:\Perl\site\lib\auto\MinGW\lib\libkernel32.a C:\Perl\site\lib\auto\MinGW\lib\libuser32.a C:\Perl\site\lib\auto\MinGW\lib\libgdi32.a C
:\Perl\site\lib\auto\MinGW\lib\libwinspool.a C:\Perl\site\lib\auto\MinGW\lib\libcomdlg32.a C:\Perl\site\lib\auto\MinGW\lib\libadvapi32.a C:\Perl\site\
lib\auto\MinGW\lib\libshell32.a C:\Perl\site\lib\auto\MinGW\lib\libole32.a C:\Perl\site\lib\auto\MinGW\lib\liboleaut32.a C:\Perl\site\lib\auto\MinGW\l
ib\libnetapi32.a C:\Perl\site\lib\auto\MinGW\lib\libuuid.a C:\Perl\site\lib\auto\MinGW\lib\libws2_32.a C:\Perl\site\lib\auto\MinGW\lib\libmpr.a C:\Per
l\site\lib\auto\MinGW\lib\libwinmm.a C:\Perl\site\lib\auto\MinGW\lib\libversion.a C:\Perl\site\lib\auto\MinGW\lib\libodbc32.a C:\Perl\site\lib\auto\Mi
nGW\lib\libodbccp32.a C:\Perl\site\lib\auto\MinGW\lib\libcomctl32.a C:\Perl\site\lib\auto\MinGW\lib\libmsvcrt.a dll.exp
C:\Perl\bin\perl.exe -MExtUtils::Command -e chmod -- 755 blib\arch\auto\DBD\Sybase\Sybase.dll

Now, you might be thinking that since it compiled it should be good huh? Nah, we test things here! ;-)

U:\build\DBD-Sybase-1.15>dmake test
dmake.exe:  makefile:  line 454:  Warning: -- Macro `BOOTSTRAP' redefined after use
C:\Perl\bin\perl.exe "-MExtUtils::Command::MM" "-MTest::Harness" "-e" "undef *Test::Harness::Switches; test_harness(0, 'blib\lib', 'blib\arch')" t/*.t

t/autocommit.t .. ok
t/base.t ........ ok
t/exec.t ........ ok
t/fail.t ........ ok
t/login.t ....... 1/6 DBD::Sybase::db ping failed: ct_cmd_alloc failed at t/login.t line 32.
t/login.t ....... ok
t/main.t ........ ok
t/multi_sth.t ... ok
t/nsql.t ........ ok
t/place.t ....... ok
t/thread.t ...... skipped: this DBD::Sybase not configured to support iThreads
t/utf8.t ........ ok
t/xblk.t ........ ok
t/xblob.t ....... ok
All tests successful.
Files=13, Tests=242, 17 wallclock secs ( 0.16 usr +  0.22 sys =  0.37 CPU)
Result: PASS

No major issues so we’re ready to build ActiveState’s PPD file and get it ready distribute:

U:\build\DBD-Sybase-1.15>dmake ppd
dmake.exe:  makefile:  line 454:  Warning: -- Macro `BOOTSTRAP' redefined after use

Zip the blib directory and name it “DBD-Sybase-1.15.zip”. Create a new directory named “MSWin32-x86-multi-thread-5.16″ and copy the zip file into it.

You need to tell PPM where to find the zip file. The PPD file is simply an XML document, so we can just update the codebase:

<softpkg NAME="DBD-Sybase" VERSION="1.15">
    <abstract>DBI driver for Sybase datasources</abstract>
    <author>Michael Peppler (mpeppler@peppler.org)</author>
    <implementation>
        <architecture NAME="MSWin32-x86-multi-thread-5.16"></architecture>
        <codebase HREF="MSWin32-x86-multi-thread-5.16\DBD-Sybase-1.15.zip"></codebase>
    </implementation>
</softpkg>

Let’s test that it actually installs using ActiveState’s PPM:

U:\build\DBD-Sybase-1.15>ppm install DBD-Sybase.ppd
Unpacking DBD-Sybase-1.15...done
Generating HTML for DBD-Sybase-1.15...done
Updating files in site area...done
   5 files installed

U:\build\DBD-Sybase-1.15>

We only need to zip up the PPD and the MSWin32-x86-multi-thread-5.16 directory listed in the PPD. It is now ready to distribute. How you do it is entirely up to you.
DBD-Sybase-1.15 for ActiveState Perl 5.16 Win32

For ActiveState Perl 64bit, you will need to use Microsoft Visual Studio. However, since the support of 64bit Perl on Windows by ActiveState is rather poor, I would recommend using the 32bit version instead.

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

$
0
0

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

sp__montableusage


Ed Barlow stored procedures: sp__indexspace updated for large tables on SAP Sybase 15x

$
0
0

Ed Barlow createdSAP Sybase the sp__indexspace stored procedure for reporting on index usage in Sybase ASE as part of the excellent Extended Stored Procedures by Ed Barlow (AKA the Ed Barlow Stored Procedures). If you have large tables, you will receive an arithmetic overflow error. I’ve updated the stored procedure to correct the error and to format the name of the tables and indexes.

$ diff indexspace.15.old indexspace.15
25a26,33
> --------------------------------------------------------------------------------------------------
> -- Vers|   Date   |      Who           | DA | Description
> -------+----------+--------------------+----+-----------------------------------------------------
> -- 1.1 |11/18/2013|  Jason Froebe      |    | Fix Arithmetic overflow error by using a bigint
> --     |          |                    |    | instead of integers.  Fix formatting to show entire
> --     |          |                    |    | table.index name
> -- 1.0 |          |  Edward M Barlow   |    | Stored procedure giving index usage
> -------+----------+--------------------+----+-----------------------------------------------------
28a37,38
> declare @max_name_size varchar(3)
> declare @exec_str varchar(2000)
64a75,77
> select @max_name_size = convert(varchar(3), max(char_length(name))) from #indexspace
> select @max_name_size
>
66,76c79,91
< select
<    convert(char(22),name)                       "Name",
<    convert(char(8),row_cnt)                                                "Rows",
<    convert(char(16),rtrim(convert(char(30),(reserved*@pagesize)/1024))+"/"+
<    rtrim(convert(char(30),(data*@pagesize)/1024))+"/"+
<    rtrim(convert(char(30),(index_size*@pagesize)/1024))) "Used/Data/Idx KB",
<    str((row_cnt*1024)/(convert(float,data+index_size)*@pagesize),6,2) "Rows/KB",
<    convert(char(12),segname) "Segment"
< from #indexspace
< where indid<=1
< order by name
---
> select @exec_str =
>     'select
>         convert(char(' + @max_name_size + '),name) "Name",
>         convert(char(20),row_cnt) "Rows",
>         convert(char(30),rtrim(convert(char(30),(reserved*@pagesize)/1024))+"/"+
>         rtrim(convert(char(30),(data*@pagesize)/1024))+"/"+
>         rtrim(convert(char(30),(index_size*@pagesize)/1024))) "Used/Data/Idx KB",
>         str((row_cnt*1024)/(convert(float,data+index_size)*@pagesize),6,2) "Rows/KB",
>         convert(char(12),segname) "Segment"
>     from #indexspace
>     where indid< =1
>     order by name'
> exec (@exec_str)
80,85c95,101
< select
<         convert(char(22),name)           "Name",
<    convert(char(8),row_cnt)                                                "Rows",
<    convert(char(16),rtrim(convert(char(30),(reserved*@pagesize)/1024))+"/"+
<    rtrim(convert(char(30),(data*@pagesize)/1024))+"/"+
<    rtrim(convert(char(30),(index_size*@pagesize)/1024))) "Used/Data/Idx KB",
---
> select @exec_str =
>     'select
>         convert(char(' + @max_name_size + '),name) "Name",
>         convert(char(20),row_cnt) "Rows",
>         convert(char(30),rtrim(convert(char(30),(reserved*@pagesize)/1024))+"/"+
>         rtrim(convert(char(30),(data*@pagesize)/1024))+"/"+
>         rtrim(convert(char(30),(index_size*@pagesize)/1024))) "Used/Data/Idx KB",
88,90c104,107
< from #indexspace
< where indid>1
< order by name
---
>     from #indexspace
>     where indid>1
>     order by name'
> exec (@exec_str)
/* Procedure copyright(c) 1995 by Edward M Barlow */

/******************************************************************************
**
** Name        : sp__indexspace
**
** Created By  : Ed Barlow
**
******************************************************************************/
:r database
go
:r dumpdb
go

IF EXISTS (SELECT * FROM sysobjects
           WHERE  name = "sp__indexspace"
           AND    type = "P")
   DROP PROC sp__indexspace
go

CREATE PROC sp__indexspace(
                @objname        varchar(92) = NULL ,
                                        @dont_format char(1) = null
                                                 )
AS
--------------------------------------------------------------------------------------------------
-- Vers|   Date   |      Who           | DA | Description
-------+----------+--------------------+----+-----------------------------------------------------
-- 1.1 |11/18/2013|  Jason Froebe      |    | Fix Arithmetic overflow error by using a bigint
--     |          |                    |    | instead of integers.  Fix formatting to show entire
--     |          |                    |    | table name + index name
-- 1.0 |          |  Edward M Barlow   |    | Stored procedure giving index usage
-------+----------+--------------------+----+-----------------------------------------------------
BEGIN

declare @pagesize int                   /* Bytes Per Page */
declare @max_name_size varchar(3)
declare @exec_str varchar(2000)

set nocount on

select  @pagesize = low
from    master..spt_values
where   number = 1
and     type = "E"

select name = o.name,
       idxname = i.name,
       owner_id = o.uid,
       row_cnt  = row_count(db_id(), i.id),
       reserved = reserved_pages(db_id(), i.id, i.indid),
       data     = data_pages(db_id(), i.id, i.indid),
       index_size = data_pages(db_id(), i.id, i.indid),
       segname = s.name,
       indid
into   #indexspace
from   sysobjects o, sysindexes i, syssegments s
where  i.id = o.id
and    (o.type = "U" or o.name = "syslogs")
and    s.segment = i.segment
and    isnull(@objname,o.name)=o.name

update #indexspace
set    name=user_name(owner_id)+'.'+name
where  owner_id>1

update #indexspace
set    name=name+'.'+idxname
where  indid!=0

update #indexspace
set    row_cnt=-1
where  row_cnt>99999999

select @max_name_size = convert(varchar(3), max(char_length(name))) from #indexspace
select @max_name_size

print "Data Level (Index Type 0 or 1)"
select @exec_str =
    'select
        convert(char(' + @max_name_size + '),name) "Name",
        convert(char(20),row_cnt) "Rows",
        convert(char(30),rtrim(convert(char(30),(reserved*@pagesize)/1024))+"/"+
        rtrim(convert(char(30),(data*@pagesize)/1024))+"/"+
        rtrim(convert(char(30),(index_size*@pagesize)/1024))) "Used/Data/Idx KB",
        str((row_cnt*1024)/(convert(float,data+index_size)*@pagesize),6,2) "Rows/KB",
        convert(char(12),segname) "Segment"
    from #indexspace
    where indid< =1
    order by name'
exec (@exec_str)

print ""
print "Non Clustered Indexes"
select @exec_str =
    'select
        convert(char(' + @max_name_size + '),name) "Name",
        convert(char(20),row_cnt) "Rows",
        convert(char(30),rtrim(convert(char(30),(reserved*@pagesize)/1024))+"/"+
        rtrim(convert(char(30),(data*@pagesize)/1024))+"/"+
        rtrim(convert(char(30),(index_size*@pagesize)/1024))) "Used/Data/Idx KB",
        str((row_cnt*1024)/(convert(float,data+index_size)*@pagesize),6,2) "Rows/KB",
        convert(char(12),segname) "Segment"
    from #indexspace
    where indid>1
    order by name'
exec (@exec_str)

drop table #indexspace

return(0)

END

go

GRANT EXECUTE ON sp__indexspace TO public
go

indexspace

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

$
0
0

Ed Barlow createdSAP Sybase the sp__helpprotect stored procedure for extracting permissions in Sybase ASE as part of the excellent Extended Stored Procedures by Ed Barlow (AKA the Ed Barlow Stored Procedures). I’ve updated it for v15 and higher:

$ diff helpprotect.10 helpprotect.15
26a23,29
> --------------------------------------------------------------------------------------------------
> -- Vers|   Date   |      Who           | DA | Description
> -------+----------+--------------------+----+-----------------------------------------------------
> -- 1.1 |11/18/2013|  Jason Froebe      |    | Updated for ASE v15
> -- 1.0 |          |  Edward M Barlow   |    | Stored procedure extracting permissions for objects
> -------+----------+--------------------+----+-----------------------------------------------------
>
135a139
> -- protecttype column can contain these values: 0 for grant with grant. 1 for grant. 2 for revoke
137c141,152
< set     ending = " WITH GRANT OPTION", protecttype_text="GRANT"
---
> set     protecttype_text =
>    case
>      when protecttype = 0
>        then "GRANT"
>      when protecttype = 1
>        then "GRANT"
>      when protecttype = 2
>        then "REVOKE"
>    end
>
> update  #protects
> set     ending = " WITH GRANT OPTION"
145c160,171
< select substring(rtrim(protecttype_text)+" "+rtrim(action_text)+" on "+rtrim(object_name(id))+column_name+" to "+rtrim(user_name(uid))+ending,1,59)
---
>         select
>          substring(
>            rtrim(protecttype_text)
>            + " "
>            + rtrim(action_text)
>            + case when id = 0 then " " else " on " end
>            + rtrim(object_name(id))
>            + column_name
>            + " to "
>            + rtrim(user_name(uid))
>            + ending
>          ,1,59)
146a173
>         where rtrim(action_text) != ""
149c176,187
< select substring(rtrim(protecttype_text)+" "+rtrim(action_text)+" on "+rtrim(object_name(id))+column_name+" to "+rtrim(user_name(uid))+ending,1,79)
---
>         select
>          substring(
>            rtrim(protecttype_text)
>            + " "
>            + rtrim(action_text)
>            + case when id = 0 then " " else " on " end
>            + rtrim(object_name(id))
>            + column_name
>            + " to "
>            + rtrim(user_name(uid))
>            + ending
>          ,1,79)
150a189
>         where rtrim(action_text) != ""
153c192,203
< select substring(rtrim(protecttype_text)+" "+rtrim(action_text)+" on "+rtrim(object_name(id))+column_name+" to "+rtrim(user_name(uid))+ending,1,131)
---
>         select
>          substring(
>            rtrim(protecttype_text)
>            + " "
>            + rtrim(action_text)
>            + case when id = 0 then " " else " on " end
>            + rtrim(object_name(id))
>            + column_name
>            + " to "
>            + rtrim(user_name(uid))
>            + ending
>          ,1,131)
154a205
>         where rtrim(action_text) != ""
/* Procedure copyright(c) 1995 by Edward M Barlow */
/*  Stored Procedure is under GPL v2 */

/******************************************************************************
**
** Name        : sp__helpprotect.sql
**
******************************************************************************/
if exists (select * from sysobjects
           where  name = "sp__helprotect"
           and    type = "P")
begin
   drop proc sp__helprotect
end
go

create procedure sp__helprotect
        @parameter varchar(30) = NULL            /* name of object or user to check     */,
        @do_system_tables char(1) = null, /* if not null will include system tbls */
        @dont_format char(1) = null,
        @groups_only char(1) = null
as
--------------------------------------------------------------------------------------------------
-- Vers|   Date   |      Who           | DA | Description
-------+----------+--------------------+----+-----------------------------------------------------
-- 1.1 |11/18/2013|  Jason Froebe      |    | Updated for ASE v15
-- 1.0 |          |  Edward M Barlow   |    | Stored procedure extracting permissions for objects
-------+----------+--------------------+----+-----------------------------------------------------

        declare @type char(2), @uid int, @msg varchar(255), @objid int

        if @parameter is NULL
                select @objid=null
        else
                select @objid = object_id(@parameter)

        /* define our table */
        select   id,uid,action,protecttype,columns,grantor,
                        column_name             = "                               "
                        ,action_text            = "                               "
                        ,protecttype_text = "                               "
                        ,ending                                 = "                               "
        into    #protects
        from    sysprotects
        where 1=2

        /* Either a passed object or all objects */
        if @objid is not null or @parameter is null
        begin

                select uid,gid into #groups from sysusers

                if @groups_only is not null
                        delete  #groups
                        where    uid != gid

                /* IT IS AN OBJECT */
                insert  #protects
                select  id,p.uid,action,protecttype,columns,grantor,"","","",""
                from    sysprotects p, #groups g
                where   id=isnull(@objid,id)
                and      p.uid = g.uid

                /* REVOKES ON COLUMNS */
                insert  #protects
                select  id,p.uid,action,2,columns,grantor,
                        "("+col_name(p.id,c.number)+")","","",""
                from            sysprotects p, master.dbo.spt_values c, #groups g
                where   p.columns is not null
                and             convert(tinyint,substring(p.columns,c.low,1)) & c.high=0
                and             c.type = "P"
                and             c.number < = 255
                and             c.number>0
                and             c.low>1
                and             col_name(p.id,c.number) is not null
                and             id=isnull(@objid,id)
                and      p.uid=g.uid

                if @do_system_tables is null and @objid is null
                        delete #protects
                        from   #protects p, sysobjects o
                        where  p.id = o.id
                        and    o.type = 'S'
        end
        else
        begin

                /* IS IT A USER */
                select @uid = uid from sysusers where name=@parameter
                if @@rowcount = 0 or @uid is null
                begin
                   print "No User Or Object Found"
                   return (1)
                end

                insert  #protects
                select  distinct id,uid,action,protecttype,columns,grantor,"","","",""
                from    sysprotects p
                where   uid=@uid
                /* and          isnull( p.columns,0x01 ) = 0x01 */

                /* REVOKES ON COLUMNS */
                insert  #protects
                select  id,uid,action,2,columns,grantor,
                        "("+col_name(p.id,c.number)+")", "","",""
                from    sysprotects p, master.dbo.spt_values c
                where isnull( p.columns,0x01 ) != 0x01
                and     convert(tinyint, substring(p.columns, c.low, 1)) & c.high = 0
                and     c.type = "P"
                and     c.number < = 255
                and     c.number>0
                and     c.low>1
                and     col_name(p.id,c.number) is not null
                and     uid=@uid

                if @do_system_tables is null
                        delete #protects
                        from   #protects p, sysobjects o
                        where  p.id = o.id
                        and    o.type = 'S'
        end

/* References etc */
delete  #protects
where   action in(151,207,222,233,236)

update  #protects
set     action_text = name
from    master.dbo.spt_values v
where   v.type='T'
and     v.number = #protects.action

update  #protects
set     protecttype_text = name
from    master.dbo.spt_values v
where   v.type='T'
and     v.number = #protects.protecttype +204

-- protecttype column can contain these values: 0 for grant with grant. 1 for grant. 2 for revoke
update  #protects
set     protecttype_text =
   case
     when protecttype = 0
       then "GRANT"
     when protecttype = 1
       then "GRANT"
     when protecttype = 2
       then "REVOKE"
   end

update  #protects
set     ending = " WITH GRANT OPTION"
where   protecttype = 0

declare @max_len int
select @max_len = max(char_length( rtrim(protecttype_text)+" "+rtrim(action_text)+" on "+rtrim(object_name(id))+column_name+" to "+rtrim(user_name(uid))+ending))
from #protects

if @max_len < 60
        select
         substring(
           rtrim(protecttype_text)
           + " "
           + rtrim(action_text)
           + case when id = 0 then " " else " on " end
           + rtrim(object_name(id))
           + column_name
           + " to "
           + rtrim(user_name(uid))
           + ending
         ,1,59)
        from #protects
        where rtrim(action_text) != ""
        order by object_name(id),protecttype_text
else if @max_len < 80
        select
         substring(
           rtrim(protecttype_text)
           + " "
           + rtrim(action_text)
           + case when id = 0 then " " else " on " end
           + rtrim(object_name(id))
           + column_name
           + " to "
           + rtrim(user_name(uid))
           + ending
         ,1,79)
        from #protects
        where rtrim(action_text) != ""
        order by object_name(id),protecttype_text
else if @max_len < 132
        select
         substring(
           rtrim(protecttype_text)
           + " "
           + rtrim(action_text)
           + case when id = 0 then " " else " on " end
           + rtrim(object_name(id))
           + column_name
           + " to "
           + rtrim(user_name(uid))
           + ending
         ,1,131)
        from #protects
        where rtrim(action_text) != ""
        order by object_name(id),protecttype_text


return (0)
go
grant execute on sp__helprotect to public
go

helpprotect

SAP Sybase ASE MDA Tables: Why is the OwnerName and OwnerID omitted in most of the MDA tables?

$
0
0

If you look SAP Sybaseat the MDA poster, you will find the object names, the database names and the like but not the owner_id or owner_name. Let’s pick on monOpenObjectActivity, one of the most heavily used mda tables

Having monOpenObjectActivity is great but what if I have two tables named the same in the same database with a different owner? Such a scenario is not uncommon in a development system when having a separate database for each developer is not practical.

A row in monOpenObjectActivity could be mydb.john.table_a or mydb.jane.table_a. While I do have the object id, there is no owner_name(DBID, OBJID) function, so I need to go into each individual database and query sysobjects. What a hassle! ASE already knows, or should know, which owner id the object belongs to so why need I have to create a dynamic query for each and every row in monOpenObjectActivity? Sure, I could create a look up table but it wouldn’t be able to handle temporary objects (e.g. #table) very well.

The following tables have Owner something in the column names:

1> select convert(varchar(30), object_name(id)) as "Object Name", convert(varchar(30), name) as "Column Name" from syscolumns where lower(name) like "%owner%"
2> go
Object Name                    Column Name
------------------------------ ------------------------------
monProcessObject               OwnerUserID
monCachedProcedures            OwnerUID
monCachedProcedures            OwnerName
monProcessProcedures           OwnerUID
monSpinlockActivity            OwnerPID
monSpinlockActivity            LastOwnerPID
monMemoryUsage                 PoolOwnerKPID
monProcessProcedures           OwnerName
monCachedObject                OwnerUserID
monCachedObject                OwnerName
sp_namecrack                   @owner

I think we need two functions: owner_name(DBID, OBJID) and owner_id(DBID, OBJID)

We also need the OwnerID and preferrably OwnerName added to the appropriate MDA tables.

What do you think?

If you’re an author of technical books, please ensure that your publisher and/or editor typesets your book contents to be readable.

$
0
0

If you’re an author of technical books, please ensure that your publisher and/or editor typesets your book contents to be readable. Especially tables and program outputs. Just because the application can’t format the output worth a damn, doesn’t mean you need to transfer it to a book:

Example from Sybase 15.0 Replication Server Administration
book_output

SAP Sybase IQ: Free “Getting started with SAP Sybase IQ server” mini course!

$
0
0

SAP Sybase has recently made available a mini course called “Getting started with SAP Sybase IQ server” for you to learn IQ, a major data warehouse product. Do yourself a favor and learn IQ. There aren’t enough IQ DBAs in the world… YET!

SAP SybaseGetting started with SAP Sybase IQ server

This how-to booklet will help you learn the basics and get started with SAP Sybase IQ as quickly as possible. You do not need to go through all of the lessons. After completing the first three sections you will have a running SAP Sybase IQ database (Don’t worry…the course comes with a database schema and data ready to load).

You can then pick and choose from the remaining lessons, based on your interest:

Please download the zip file for all the “ Metadata, Data and Queries for Lessons in the Quick Start Guide ”

To benefit from this book, you should be familiar with the following concepts:

  • Relational database systems
  • Database schemas
  • SQL

HOWTO: Install SAP Sybase Control Center 3.2.7 on Windows 8

$
0
0

SAP/Sybase doesn’t SAP Sybaseofficially support running SCC on Windows 8. This seems to be more of an issue with the InstallShield installer. Seriously, why do people still use InstallShield??

If you try installing SCC 3.2x on Windows 8, you’ll get a nasty error when you run setup.exe or setupconsole.exe:

scc_setup

scc_setup_details

You *can* install and run SCC 3.2.x on Windows 8 if you are willing to run the 32bit version of SCC. You will need to install Microsoft C++ 2005 SP1 x86.

Next, open a cmd.exe as Administrator and run “setup.exe -i gui”

Sybase ASE: Adding log to a completely log full database – errors 1105 and 3475 “There is no space available in SYSLOGS”– SOLVED

$
0
0

When SAP Sybasea sybase database’s log is completely full, you won’t be able to add any log space to it. Attempting to add to the log produces a 3475 error:
 

00:0006:00000:00001:2014/01/08 09:03:09.09 server  ERROR: Can't get a new log page in db 4. num_left=17 num_in_plc=17.
00:0006:00000:00001:2014/01/08 09:03:09.09 server  Error: 1105, Severity: 17, State: 7
00:0006:00000:00001:2014/01/08 09:03:09.09 server  Can't allocate space for object 'syslogs' in database 'mydb' because 'logsegment' segment is full/has no free extents. If you ran out of space in syslo
gs, dump the transaction log. Otherwise, use ALTER DATABASE to increase the size of the segment.
00:0006:00000:00001:2014/01/08 09:03:09.09 server  Error: 3475, Severity: 21, State: 7
00:0006:00000:00001:2014/01/08 09:03:09.09 server  There is no space available in SYSLOGS to log a record for which space has been reserved in database 'mydb' (id 4). This process will retry at interval
s of one minute.

 
So what to do? If you separate your data and log segments, you will need to temporarily add the log segment to a data device so the database can recover. Once it recovers, we can add space to the log and remove the log segment from the data device. For good measure, we run dbccs to correct any allocation issues that may be contributing to the out of log space.
 
Add the log segment to a data device (use sp_helpdb dbname to determine which data device has space):

exec sp_configure "allow updates", 1
go
update sysusages set segmap = 7 where dbid = 4 and lstart = 1492992
go
checkpoint
go
shutdown with nowait
go

Add space to the log:

alter database mydb log on mydevicel001 = 500
go

 
Before we do anything else, let’s run dbccs. Of course, you will want to run the dbccs without the fix option to identify if there are other issues prior to running with the fix:

exec kill_user_connections mydb
exec kill_user_connections mydb
exec kill_user_connections mydb
exec kill_user_connections mydb
exec kill_user_connections mydb
exec sp_dboption mydb, 'dbo use', true
exec sp_dboption mydb, 'single user', true
dbcc traceon(3604)
dbcc checkdb(mydb, fix_spacebits)
dbcc checkalloc(mydb, fix)
exec sp_dboption mydb, 'dbo use', false
exec sp_dboption mydb, 'single user', false
go

If no lingering issues, we can remove the log segment from the data device:

exec sp_dboption mydb, 'single user', true
go
use mydb
go
exec sp_dropsegment logsegment, mydb, mydeviced005
go
use master
go
exec sp_dboption mydb, 'single user', false
go

SAP is fixing Bug CR 756957 in ASE 15.7 SP110 that may be the root cause of the 3475 error:

In certain circumstances, databases, including system databases, can incorrectly get into LOG SUSPEND mode, issuing message: “Space available in the log segment has fallen critically low in database ‘ < dbname > ‘. All future modifications to this database will be suspended until the log is successfully dumped and space becomes available.” This may happen even though there is much unreserved space in the database. The problem may also manifest in 3475 errors: “There is no space available in SYSLOGS to log a record for which space has been reserved in database < dbname > .”


How to Add logins/users to SAP Sybase IQ and copy the password from another system!

$
0
0

You will need to create one or more application groups. In the below example we create the mygroup group:

sp_iqaddlogin "mygroup", null;
GRANT CONNECT TO "mygroup";
GRANT GROUP TO "mygroup";

After that you can create a user:

sp_iqaddlogin "henry", null;
GRANT CONNECT TO "henry" IDENTIFIED BY 'password';

Note that if you are copying a user from one IQ system to another and want to keep the password, this is a simple thing. You just need to grab the password column of sysuser for the user in question:

select password
from sysuser 
where user_name = "henry";
0x0112fd265040a70f82873c922d2aa5d1cbae597ff18217687d3e0ca45b4e246b74198f1713

You will need to escape each byte in order to add the password:

GRANT CONNECT TO "henry" 
IDENTIFIED BY ENCRYPTED 
'\x01\x12\xfd\x26\x50\x40\xa7\x0f\x82\x87\x3c\x92\x2d\x2a\xa5\xd1\xcb\xae\x59\x7f\xf1\x82\x17\x68\x7d\x3e\x0c\xa4\x5b\x4e\x24\x6b\x74\x19\x8f\x17\x13';

Now we need to add henry to the mygroup group:

GRANT MEMBERSHIP 
IN GROUP "mygroup" to 'henry';

Any and all object permissions should be granted to the group not the user.

SAP Sybase IQ SA CR 728597 / Linux Kernel direct i/o bug & huge pages

$
0
0

Last year, April -> October, I asked the question about IQ supporting Huge Pages on Linux. It was mentioned that under SA CR 728597 and Red Hat Bug 891857 that there was a bug in the Linux kernel handling of direct I/O while using transparent huge memory pages (a variant of Linux Huge memory pages).

CR 728597:
This problem is related to a possible bug in the transparent huge pages (THP) feature introduced in these operating system versions. Red Hat bug 891857 has been created to track this issue.

The problem can be triggered by calling an external environment, xp_cmdshell, or other procedure that causes a fork while other I/O is occurring. A known limitation with the Linux kernel limits the use of fork while doing O_DIRECT I/O operations. Essentially what can happen is that the data can come from or go to the wrong process’ memory after the fork. SQL Anywhere performs O_DIRECT I/O operations according to the documented safe usage. However, THP appears to cause further problems and the O_DIRECT I/O data comprising database page reads/writes appears to get lost.

http://scn.sap.com/thread/3338917 and http://froebe.net/blog/2013/06/17/does-anyone-have-any-details-on-redhat-linux-bug-891857/

Does anyone know the status of this ongoing FIVE year old issue?

http://scn.sap.com/thread/3505418

SAP Sybase ASE 15.7: Unquiesce / quiesce not working

$
0
0

Typically there is a set of systems thatSAP are flashed from one system to another. The basic operation is: quiesce the databases in the source Sybase ASE instance, make a copy of the disk volume groups at the SAN level, move that volume group copy to the destination system, vary on the devices, start Sybase ASE and unquiesce the databases.

A set of devices were added to the source system but the volume group definition on the destination system wasn’t updated so a number of (raw) devices weren’t available to the destination Sybase ASE instance. Well, Sybase ASE did complain that the devices weren’t available but the automated unquiesce job called quiesece database.. release anyways. So it should have reported an error and done nothing further… right? Nope, the quiesce command removed the quiesce tag that is used to release the quiesce.

The destination volume group was refreshed and the devices were made available.

sp_helpdb showed:

1> sp_helpdb
2> go
 name           db_size       owner dbid  created      durability  lobcomplvl inrowlen status                                                               
 -------------- ------------- ----- ----- ------------ ----------- ---------- -------- -------
....
 goober_db          456.0 MB sa       13 Apr 30, 2012 full              NULL     NULL offline, quiesce database
....

Can we online it? Nope:

1>online database goober_db
2> go
Msg 921, Level 14, State 1:
Server 'super_duper_db_of_doom', Line 1:
Database 'goober_db' has not been recovered yet - please wait and try again.

Let’s try to find out what the quiesce tag is. We can check in monOpenDatabases or in dbcc resource. monOpenDatabases is a whole lot easier to read:

1> select DBID, QuiesceTag from master..monOpenDatabases where DBID = 13
2> go
 DBID        QuiesceTag
 ----------- ------------------------------
          13 NULL

No luck there, so let’s see what dbcc resource says that the status is. Lots and lots of output but it says that the database is recovering under spid 18:

1>dbcc traceon(3604)
2>go
1>dbcc resource
2>go
....
dbid = 13
Parallel thread spid: 18
Status: 0x30 ((0x00000020 (REC_ITEM_ONL_IMMEDIATELY), 0x00000010 (REC_ITEM_RECOVERING)))
....

I didn’t see spid 18 about in sysprocesses but that isn’t a guarantee that it isn’t in some state of release. Let’s kick out a stacktrace for this spid just in case. I would have been surprised if there was a stacktrace:

1> dbcc stacktrace(18)
2> go
Msg 3659, Level 16, State 3:
Server 'super_duper_db_of_doom', Line 1:
The spid 18 does not exist.

At this point, I changed the status and status2 columns of master..sysdatabases to 0 and restarted the instance. At worst, it should put the database into suspect mode. Well, the database was back in not recovered / recovering with quiesce mode.

Thinking I might have to reflash the set of devices I rebooted the database thinking perhaps we can have it rescan the dbtable page (or is it dbinfo? After nearly twenty years I still get the two names mixed up)

1>dbcc dbreboot(reboot, goober_db)
2>go

---------- Shutting Down Database 'goober_db' ----------
---------- Re-starting Database 'goober_db' With Recovery ----------
Recovering database 'goober_db'.
Started estimating recovery log boundaries for database 'goober_db'.
Database 'goober_db', checkpoint=(2154102095, 15), first=(2154102095, 15), last=(2154102095, 15).
Completed estimating recovery log boundaries for database 'goober_db'.
Started ANALYSIS pass for database 'goober_db'.
Completed ANALYSIS pass for database 'goober_db'.
Started REDO pass for database 'goober_db'. The total number of log records to process is 1.
Completed REDO pass for database 'goober_db'.
Recovery of database 'goober_db' will undo incomplete nested top actions.
Started filling free space info for database 'goober_db'.
Completed filling free space info for database 'goober_db'.
Started cleaning up the default data cache for database 'goober_db'.
Completed cleaning up the default data cache for database 'goober_db'.
Recovery complete.
Database 'goober_db' is now online.
---------- Operation on Database 'goober_db' Completed Successfully ----------

What??!? It’s online?

1> sp_helpdb
2> go
 name           db_size       owner dbid  created      durability  lobcomplvl inrowlen status                                                               
 -------------- ------------- ----- ----- ------------ ----------- ---------- -------- -------------------------------------------------------------------------------------------
....
 goober_db          456.0 MB sa       13 Apr 30, 2012 full              NULL     NULL no options set                    
....

Obviously dbcc reboot is doing something different in prep for recovery that restarting the instance does. My guess is that the dbtable is examined and updated/refreshed with the dbreboot dbcc where it is not for a reboot. I’ve opened a ticket with SAP about this. I’ll update this when some sort of answer is available

SAP Sybase IQ – dbcc for IQ? Yes! Just use sp_iqcheckdb

$
0
0

If you’re coming from Microsoft SAP SybaseSQL Server or Sybase ASE, SAP’s IQ doesn’t have the slew of dbcc commands you might expect. It rolls up all the pertinent dbccs into a single stored procedure. sp_iqcheckdb has four operational modes with a granularity at the database, table or index level:

  1. In check mode, sp_iqcheckdb performs an internal consistency check on all IQ indexes and checks that each database block has been allocated correctly. All available database statistics are reported. This mode reads all data pages and can detect all types of allocation problems and most types of index inconsistencies. Check mode should run considerably faster than verify mode for most databases.
  2. In verify mode, sp_iqcheckdb performs an intra-index consistency check, in addition to internal index consistency and allocation checking. All available database statistics are reported. The contents of each non-FP index is verified against its corresponding FP index(es). Verify mode reads all data pages and can detect all types of allocation problems and all types of index inconsistencies.
  3. In allocation mode, sp_iqcheckdb checks that each database block is allocated correctly according to the internal physical page mapping structures (blockmaps). Database statistics pertaining to allocation are also reported. This mode executes very quickly. Allocation mode, however, does not check index consistency and cannot detect all types of allocation problems.
  4. When the Sybase IQ server runs in single-node mode, you can use dropleaks mode with either a database or dbspace target to reset the allocation map for the entire database or specified dbspace targets. If the target is a dbspace, then the dropleaks operation must also prevent read-write operations on the named dbspace. All dbspaces in the database or dbspace list must be online.

No changes are actually performed with the exception of the dropleaks mode. If check or verify detects an issue with allocation, you will need to run sp_iqcheckdb in the dropleaks mode while the database is in single user mode. For any issues with indexes, use sp_rebuildindex on both the index and possibly the affected column of the table.

By default output of sp_iqcheckdb will go to the (instance_name).iqmsg log file but you can redirect it to its own file for easier reading:

sp_iqcheckdb 'verify database' ># filename

Please note that the file name may not contain spaces or special symbols and the path will be local to the IQ box. So, unless you want to hunt for your checkdb output file, please specify the full path. No, you can not put the filename in any type of quotes and you can’t escape interesting characters.

Unless you’re under a serious time constraint, always run sp_iqcheckdb in verify mode to determine structural issues with your IQ databases.

Preliminary REVIEW: SAP’s HANA – In memory database with local/remote data stores

$
0
0

Recently I attended a quite well done presentation regarding SAP’s HANA data storage product and scoured the various websites mentioning HANA. I’m not going to go over the that as all that information is really on SAP’s website.

I was inspired to get access to it last night from a friend so this preliminary review is only from a few hours of hands-on playing with it. Perhaps if time allows I’ll perform an in depth analysis of it.

HANA is a memory resident hybrid OLTP/OLAP/DSS system with aspects of being able to quickly load data from a myriad of sources into memory.

You’re currently limited to 2TB of memory for the data AND any memory required to run HANA including sorting tables. If you’re using SAP business applications, this limit is 4TB. The systems have to be certified by SAP and the software will be installed by the hardware vendor unless you’re certified. There are ways to determine exactly how much memory you’re using but like Sybase ASE’s MDA tables, getting actual utilization requires a lot of patience and hair pulling.

The platform is RedHat Linux on Intel hardware from HANA certified hardware vendors (currently nine vendors).

What happens if the box goes down? There is local storage (or SAN type storage if you prefer) that the memory resident database loads initially from and writes to periodically. When I killed HANA it took a few minutes to recover but most of this was reading from the local storage directly into memory. At this point, I’m not certain as to what extent, if any, that HANA checks the data on load. It seems to perform of checksum on the log records on recovery but I wasn’t able to verify in the time I had available.

In SAP’s marketing literature it says that CPU caches are specifically targeted for high performance of certain types of operations whereas other DBMS systems do not. Again, I didn’t have time to determine how HANA implements it. There are a couple methods that can be done to perform this:

  1. Run part of a process in kernel space, think kernel module, but this can be quite risky not only from a stability aspect but also security wise. In the early days of Linux, this wasn’t uncommon, now days it is quite rare.
  2. Write parts of your application, the really time sensitive parts, in assembly language utilizing the capabilities to control what goes where on the cpu to some extent. You’ll find this often with multimedia or cpu intensive applications.

SAP HANA isn’t unique in any of these aspects as all of these have been around for a number years before SAP developed HANA but it is unique that it implements all of them. Is it worth the cost of the hardware and software licensing? It depends.

If you care about performance and willing to pay for it, HANA may be a very good fit for your company.

Viewing all 102 articles
Browse latest View live


Latest Images