SybaseASE系统表的应用

SybaseASE系统表的应用
一、问题背景
在排查江西、湖南地区数字法院系统数据库CPU高和慢SQL问题时,发现系统中有很多简单的全表扫描SQL,原因是一些子表外键没有索引导致。
添加缺失外健索引成为当务之急。数字法院系统有几十个SMD文档,2000多张表,上万个字段,人工检查SMD文档工作量大,效率低。而sybase的sp_help、sp_helpindex又只能查看单个表的索引情况,没有办法检查整个数据库的索引情况。
 
二、解决思路
查阅sp_help和sp_helpindex的源代码发现,可以通过ase的系统表、系统函数来获取到整个数据的建立索引情况,然后通过系统表关联得出没有建立外健索引的字段。
       用到的系统表有:
1.sysobjects
系统对象表,每个表、视图、存储过程、触发器等数据库对象都在sysobjects中有一行。
主要字段如下:
列名    字段类型    描述
name    varchar(255)    对象名
id    int    对象ID
type    char(2)    对象类型,U:用户表、V:系统表、V:视图
 
2.syscolumns
系统列表,每个表、视图中的每一列和过程的每个参数在syscolumns中都有对应的一行。
主要字段如下:
列名    字段类型    描述
id    int     所属表或者过程的id
colid    smallint    列id
name    varchar(255)    列名
type    tinyint    存储类型
length    int    物理长度
 
3.sysindexes
系统索引表,每个聚簇索引、非聚簇索引、没有聚簇索引的表、包含text\image列的表都在sysindexes中有对应的一行。注意:该表中没有索引的key信息,即索引建立在表的哪些字段上。
主要字段如下:
列名    字段类型    描述
id    int    所属表ID或索引ID
indid    smallint    表内索引id,0:表、1:页锁表聚簇索引、>1:DOL锁表索引、255:text\image\log。表内索引id的范围是1~254,一张表最多能建立254个索引。
keycnt    smallint    键的个数。取值范围是1~31,复合索引最多能包含31个列。
name    varchar(255)    表名或索引
status    smallint    内部系统状态信息
status2    smallint    内部系统状态信息
status3    smallint    内部系统状态信息
 
4.spt_values
系统内部值表,相当于业务系统中的“单值代码”表。根据type、number 字段 查出其他表中status 对应的name。
主要字段如下:
列名    字段类型    描述
name    varchar(255)    系统内部状态值对应名称
type    char    系统内部状态类型
number    int    系统内部状态值
 
   系统函数有:
1.index_col(obj_name,index_id,key_# [,user_id])
返回表、视图中索引的列名。
参数名    描述
object_name    表名或者视图名
index_id    表sysindex中indid的值
key_#    键值顺序。如sysindex中keycnt为3,说明该索引包含3个列,key_#需要依次传入1、2、3,依次获得第一列、第二列、第三列名称
user_id    object_name的所有者id,可选
 
2.index_colorder(obj_name,index_id,key_# [,userid])
返回索引中列的desc/asc顺序。
参数名    描述
object_name    表名或者视图名
index_id    表sysindex中indid的值
key_#    键值顺序。如sysindex中keycnt为3,说明该索引包含3个列,key_#需要依次传入1、2、3,依次获得第一列、第二列、第三列名称
user_id    object_name的所有者id,可选
三、解决步骤
第一步:创建表T_SYS_TABLE_INDEX 用于存储库中所有表的索引情况,主要字段如下:
列名    类型    描述
table_name    varchar(255)    表名
table_id    int    表id
index_name    varchar(255)    索引名称
index_keys    varchar(1024)    索引列
index_descriptions    varchar(68)    索引描述
index_created    datetime    索引创建时间
 
 
第二步: 创建sp_genIndexInfo存储过程,收集单个表的索引信息。
  主要过程为:
1.循环获取表的所有索引id
select @indid = min(indid) from sysindexes where id = object_id(@objname) and indid > 0 and indid < 255
 
while @indid is not NULL
begin
    ----------------------------
    --获取单个索引的索引键值逻辑
    ----------------------------
    select @lastindid = @indid
    select @indid = NULL
    select @indid = min(indid) from sysindexes where id = object_id(@objname) and indid > @lastindid and indid < 255
END
 
2.获取单个索引的索引键值逻辑
while @i <= 31
    begin
        select @thiskey = index_col(@objname, @indid, @i)
        if (@thiskey is NULL)  
        begin
            goto keysdone
        end
        if @i > 1
        begin
            select @keys = @keys + ", "  
        end
        select @keys = @keys + @thiskey
        select @sorder = index_colorder(@objname, @indid, @i)
        if (@sorder = "DESC")
            select @keys = @keys + " " + @sorder
        select @i = @i + 1
    end
    keysdone:
        set nocount off
 
3.将索引信息存入T_SYS_TABLE_INDEX表
insert into T_SYS_TABLE_INDEX
        select @objname,object_id(@objname),name, @keys, @inddesc, maxrowsperpage, fill_factor,
            isnull(res_page_gap,0), crdate,  
            case when (status3 & 8 = 8) then "Local Index"
                 else "Global Index"
            end
            from sysindexes where id = object_id(@objname) and indid = @indid
 
第三步:循环获取当前库中每一张表的索引信息
DECLARE @table_name VARCHAR(600)
DECLARE @table_id INT
DECLARE @last_table_id INT  
select @table_id = min(id) from sysobjects where  type = 'U'
while @table_id is not NULL
BEGIN
  SELECT @table_name = name FROM sysobjects WHERE type ='U' AND id = @table_id
  EXEC sp_genIndexInfo @table_name
  select @last_table_id = @table_id
  select @table_id = NULL
  select @table_id = min(id),@table_name=name from sysobjects where id > @last_table_id and type = 'U'
END
 
第四步:查询未建索引的表和字段
SELECT db_name() AS dbname,obj1.name AS table_name,cols.name AS col_name  
FROM syscolumns cols LEFT JOIN sysobjects obj1 ON cols.id = obj1.id  
WHERE obj1.type = 'U'  
AND cols.name like 'C_BH_%' AND cols.length = 32
AND NOT EXISTS (
  SELECT 1 FROM  T_SYS_TABLE_INDEX tis WHERE tis.table_id = obj1.id AND charindex(cols.name,tis.index_keys) >0
)
ORDER BY obj1.name desc
 
四、结果展示
1、全库已建索引信息
 
2、全库未建外键索引信息
 
通过程序或脚本可以将未建索引的外键字段批量生成建立索引脚本。
五、结论
Sybase ASE的系统表相当于其他DBMS的数据字典,记录和展示了数据库的元数据信息,利用这些信息DBA和程序员可以做很多的批量处理工作,减少手工劳动,提高效率!

posted @ 2017-05-31 14:46  wangzhen3798  阅读(265)  评论(0编辑  收藏  举报