暂无图片
暂无图片
2
暂无图片
暂无图片
暂无图片

利用python生成ORACLE DBTIME曲线图并保存为图片

原创 red_hope 2021-01-18
2492

在自动化巡检中,我们需要生成几个图形,直观反映数据库性能、表空间、逻辑读、物理读趋势等。dbtime的曲线图就是其中一只,dbtime可以反馈数据库在各个时段的繁忙程度,绘制一个张dbtime曲线图,可以很好地了解数据库繁忙程度。
话不多说,开始。

第一步:安装pyecharts

目前可下载的最新版本为1.9.0:
image.png
本程序是基于pycharts 的1.9.0开发。
pyecharts是基于python非常好的图标插件,相信信息可以参考:
https://pyecharts.org/#/zh-cn/intro
本次我们用到折线图,效果如下:
image.png
该折线图上,反映了数据库实例平均dbtime/s及最大、最小dbtime。dbtime/s在awr中是反应数据库压力的一个重要指标。

第二步:采集数据库dbtime

用每个dba自己喜欢的形式采集dbtime数据,我用的脚本如下:

select a.instance_number,to_char(end_interval_time,'yyyy-mm-dd-hh24:mi') start_time,
round((CASE 
  when round((b.value-a.value)/1000000/
    round((to_date(to_char(c.END_INTERVAL_TIME, 'yyyy-mm-dd hh24:mi:ss'),
                      'yyyy-mm-dd hh24:mi:ss') -
             to_date(to_char(c.BEGIN_INTERVAL_TIME,
                              'yyyy-mm-dd hh24:mi:ss'),
                      'yyyy-mm-dd hh24:mi:ss')) * 24 * 60,
             2),2)< 0 then 
    0
  else
    round((b.value-a.value)/1000000/
    round((to_date(to_char(c.END_INTERVAL_TIME, 'yyyy-mm-dd hh24:mi:ss'),
                      'yyyy-mm-dd hh24:mi:ss') -
             to_date(to_char(c.BEGIN_INTERVAL_TIME,
                              'yyyy-mm-dd hh24:mi:ss'),
                      'yyyy-mm-dd hh24:mi:ss')) * 24 * 60,
             2),2)
end)/(round((to_date(to_char(c.END_INTERVAL_TIME, 'yyyy-mm-dd hh24:mi:ss'),'yyyy-mm-dd hh24:mi:ss')
  -  to_date(to_char(c.BEGIN_INTERVAL_TIME,'yyyy-mm-dd hh24:mi:ss'), 'yyyy-mm-dd hh24:mi:ss')) * 24 * 60,2)),2)
 "dbtime/s",
  a.SNAP_ID,
  a.con_id
from cdb_hist_sys_time_model a,cdb_hist_sys_time_model b ,cdb_hist_snapshot c
where a.stat_name='DB time' and b.stat_name='DB time' 
      and a.dbid=b.dbid and a.dbid=(select dbid from v$database)
      and a.instance_number= b.instance_number and c.instance_number=b.instance_number
      and a.snap_id=c.snap_id
      and b.snap_id=c.snap_id+1 
      and C.END_INTERVAL_TIME>=sysdate-7
      order by a.instance_number,a.SNAP_ID asc; 

采集的到的样式如下:
image.png

INSTANCE_NUMBER是实例号,START_TIME是snap开始时间,dbtime/s是每秒的dbtime,snap_id及con_id是snap编号及pdb编号(12c以下版本无con_id,可以将去掉该字段,同时把视图中的cdb改成dba即可。)

第三步:编写python代码

(1)遍历有几个实例

有几个实例,绘制几条线:

    number = []
    for lss in lines:
        m = lss.replace('\n', '')
        if len(lss)>10:
            inst_id = lss.split()[0]
            if inst_id not in number:
                number.append(inst_id)

将遍历出的实例编号放到number中,然后以nunber为外层循环,逐层读取START_TIME及dbtime/s,START_TIME数据做x轴,dbtime/s数据库做y轴线。

(2)读取x轴、y轴数据到list中

将时间及cost对应读取到list中,样式如下:
{‘time_id’: ‘2021-01-07-10:00’, ‘cost’: ‘.03’}

    ALL_DATA = []
    # 初始化图形组件
    line = Line()
    for j in range(len(number)):
        inst_id_w = number[j]
        for lss in lines:
            lss = lss.replace('\n', '')
            inst_id_n = lss.split()[0]
            if inst_id_w == inst_id_n:
                time_id = lss.split()[1]
                cost = lss.split()[2]
                ALL_DATA.append({"time_id": time_id, "cost": cost})
        show_data = ALL_DATA

这里,我们用二维数组以key-value的方式存放了dbtime数据。方法中用到的关键函数就是split函数,用空格分割字符串,分割后,第一个字段为实例号,第二个字段是时间,第三个是dbtime/s,第四个是snap,第五个是con_id.
然后从这个list中,分别提取x轴、y轴数据:

data_time_x = list(map(lambda ALL_DATA: ALL_DATA["time_id"], show_data))
data_dbtime_y = list(map(lambda ALL_DATA: float(ALL_DATA["cost"]), show_data))

当然,可以定义两个不同的list,这样分别给x,y轴赋值,就不用这么麻烦了。

(3)赋值x轴,y轴数据

        line.add_xaxis(data_time_x)
        line.add_yaxis(f'实例{inst_id_w}', data_dbtime_y, is_selected=True)
        line.set_global_opts(title_opts=opts.TitleOpts(title=f"{dbname}库DBTIME变化趋势图",
                                                       subtitle='DBTIME 通过与cpu及时间的比较,计算数据库的繁忙程度'),
                            xaxis_opts = opts.AxisOpts(
                                splitline_opts=opts.SplitLineOpts(is_show=True)
                            ),  # 设置x轴
                                         yaxis_opts = opts.AxisOpts(
                                splitarea_opts=opts.SplitAreaOpts(is_show=True, areastyle_opts=opts.AreaStyleOpts(opacity=1))
                            ),  # 设置y轴
                            toolbox_opts = opts.ToolboxOpts(is_show=True),
        )
        line.set_series_opts(
            markpoint_opts=opts.MarkPointOpts(
                data=[
                    opts.MarkPointItem(type_="max", name="最大值"),
                    opts.MarkPointItem(type_="min", name="最小值"),
                ]),
            markline_opts=opts.MarkLineOpts(
                data=[
                    opts.MarkLineItem(type_="average", name="平均值"),
                ]
            ),
        )
        ALL_DATA = [] #本次循环完成后,将ALL_DATA 数据清空,防止已有数据干扰下一个实例

(4)生成图片

图片有两种方式生成,一种是html形式,一种是gif形式,期中gif形式用于自动巡检报告,作为图片,可以自动插入到巡检报告中。

    f_out = f'D:\\巡检自动化\\dbtime_list\sql_cost_line_{dbname}'
    line.render(f'{f_out}.html')
    make_snapshot(snapshot, line.render(), f'{f_out}.gif')

如果要将生成的图片插入到自动化巡检生成的word中,可以采用如下方式:

Docx.add_picture(f'D:\巡检自动化\dbtime_list\\sql_cost_line_{db_name}.gif', width=Inches(6.0),height=Inches(2.0))

这一部分设计到python对docx的操作,感兴趣的可以阅读笔者之前的文章。

(5)完整函数代码

最后,放送上“利用python生成ORACLE DBTIME曲线图并保存为图片”函数全部代码:

from pyecharts import options as opts
from pyecharts.charts import Line
from pyecharts.render import make_snapshot
from snapshot_selenium import snapshot

def show_db_time(str_dbtime,dbname):
   #	str_dbtime是传入的采集sql执行的全部结果,包括sql head等信息,因此会掐头、去尾
    print('正在绘制dbtime趋势图,该趋势图反应数据库繁忙程度...')
    lines = str_dbtime[0].splitlines()
    lines = lines[4:len(lines)-4]
    number = []
    for lss in lines:
        m = lss.replace('\n', '')
        if len(lss)>10:
            inst_id = lss.split()[0]
            if inst_id not in number:
                number.append(inst_id)

    ALL_DATA = []
    # 初始化图形组件
    line = Line()
    for j in range(len(number)):
        inst_id_w = number[j]
        for lss in lines:
            lss = lss.replace('\n', '')
            inst_id_n = lss.split()[0]
            if inst_id_w == inst_id_n:
                time_id = lss.split()[1]
                cost = lss.split()[2]
                ALL_DATA.append({"time_id": time_id, "cost": cost})
        # 一个sql_id相关数据获取完成,开始画图
        show_data = ALL_DATA

        data_time_x = list(map(lambda ALL_DATA: ALL_DATA["time_id"], show_data))
        data_dbtime_y = list(map(lambda ALL_DATA: float(ALL_DATA["cost"]), show_data))
        #if i == 0:
        line.add_xaxis(data_time_x)
        #    i = i +1
        line.add_yaxis(f'实例{inst_id_w}', data_dbtime_y, is_selected=True)
        line.set_global_opts(title_opts=opts.TitleOpts(title=f"{dbname}库DBTIME变化趋势图",
                                                       subtitle='DBTIME 通过与cpu及时间的比较,计算数据库的繁忙程度'),
                            xaxis_opts = opts.AxisOpts(
                                splitline_opts=opts.SplitLineOpts(is_show=True)
                            ),  # 设置x轴
                                         yaxis_opts = opts.AxisOpts(
                                splitarea_opts=opts.SplitAreaOpts(is_show=True, areastyle_opts=opts.AreaStyleOpts(opacity=1))
                            ),  # 设置y轴
                            toolbox_opts = opts.ToolboxOpts(is_show=True),
        )
        line.set_series_opts(
            # 设置系列配置
            markpoint_opts=opts.MarkPointOpts(
                data=[
                    opts.MarkPointItem(type_="max", name="最大值"),
                    opts.MarkPointItem(type_="min", name="最小值"),
                ]),
            markline_opts=opts.MarkLineOpts(
                data=[
                    opts.MarkLineItem(type_="average", name="平均值"),
                ]
            ),
        )
        ALL_DATA = []

    f_out = f'D:\\巡检自动化\\dbtime_list\sql_cost_line_{dbname}'
    line.render(f'{f_out}.html')
    make_snapshot(snapshot, line.render(), f'{f_out}.gif')
    if len(data_dbtime_y) > 0:
        return data_dbtime_y
    else:
        return [0]

最后修改时间:2021-01-18 15:42:26
「喜欢这篇文章,您的关注和赞赏是给作者最好的鼓励」
关注作者
【版权声明】本文为墨天轮用户原创内容,转载时必须标注文章的来源(墨天轮),文章链接,文章作者等基本信息,否则作者和墨天轮有权追究责任。如果您发现墨天轮中有涉嫌抄袭或者侵权的内容,欢迎发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论