openGauss 之blks_hit统计实现的代码走读

一. 前言

​         在openGauss中,select *  from pg_stat_database可以看到每个数据库缓存命中率(blks_hit)的统计,如下所示:

       本文主要走读openGauss的代码来了解openGuass是在怎样进行缓存命中率的统计的。

二.  数据库级别缓存命中率(blks_hit)统计实现流程

​        在openGuass中,每一个表(Relation)的结构体有一个字段pgstat_info,pgstat_info->t_counts中会存放着relation的各种统计信息,如元祖的读取数量,缓存的命中数量等,如下是整个代码的实现流程。

​        1. 首先在回话初始化的时候,pgstat_initstats函数会在回话中,创建pgstat_info的内存空间并且赋值给relation->pgstat_info,代码流程如下所示:

pgstat_initstats
  rel->pgstat_info = get_tabstat_entry
    hash_entry = (TabStatHashEntry*)hash_search(u_sess->stat_cxt.pgStatTabHash, &rel_key);
       return entry   // entry就是relation的pgstat_info

       2.  在读取数据块的时候,传入realtion,并且根据在buffer_read_extended_internal判断读取的是缓存还是磁盘来对改relation的t_blocks_hit的统计之,代码流程如下所示:

buffer_read_extended_internal
    ReadBuffer_common(...&hit...);
        bufHdr = BufferAlloc(&found);    
        if (found) {
            *hit = true;   // 如果需要读取的block在buff中能够找到,则将hit置上
        }
    if (hit) {
        pgstat_count_buffer_hit(reln);    // 如果hit被置上,则对改relation的t_blocks_hit统计信息进行加1
    }      

    3.  在StatementFlush现成中定位将定期发送将所有表的统计信息发送给PgstatCollectorMain现成汇总:

StatementFlush
   pgstat_report_stat
     for (tsa = u_sess->stat_cxt.pgStatTabList; tsa != NULL; tsa = tsa->tsa_next) {
         for (i = 0; i < tsa->tsa_used; i++) {
            memcpy_s(&this_ent->t_counts, &entry->t_counts)
            pgstat_send_tabstat(this_msg);
         }
      }

   4.  PgstatCollectorMain收到信息之后,第db下所有的包的t_blocks_hit进行汇总,并且存放着u_sess->stat_cxt.pgStatDBHash中

pgstat_recv_tabstat
    dbentry = pgstat_get_db_entry(msg->m_databaseid, true);
        result = (PgStat_StatDBEntry*)hash_search(u_sess->stat_cxt.pgStatDBHash, &databaseid);
        return result;
    for (i = 0; i < msg->m_nentries; i++) {
       tabentry->blocks_hit = tabmsg->t_counts.t_blocks_hit;
    }

    5.  select * from pg_stat_database 的时候通过pg_catalog.pg_stat_get_db_blocks_hit函数从pgStatDBHash中获取到数据库的汇总后的t_blocks_hit统计信息,如下所示:

pg_stat_get_db_blocks_hit
    if ((dbentry = pgstat_fetch_stat_dbentry(dbid)) == NULL)
        result = 0;
    else
        result = (int64)(dbentry->n_blocks_hit);   // dbentry 存放着的就是步骤4的所有表信息的汇总    
三.  单条查询缓存命中率统计

​       执行单条查询比如explain (ANALYZE true, buffers true) select * from t1时,可以看到单条sql的缓存命中率,如下所示:

       单条sql的缓存命中率实现比较简单,单条sql的缓存命中命中率是存放在u_sess->instr_cxt.pg_buffer_usage->shared_blks_hit中的,explain的时候也是直接从u_sess->instr_cxt.pg_buffer_usage->shared_blks_hit中读取,如下是实现流程:

  1. 初始化planstate的时候,将当前u_sess->instr_cxt的当前缓存统计信息保存到planstate->instr->bufusage_start ,用于后边求差值作为实际的统计信息:

InstrStartNode
   if (instr->need_bufusage)
      instr->bufusage_start = *u_sess->instr_cxt.pg_buffer_usage;

    2. 执行sql,其中根据是否命中缓存,直接修改u_sess->instr_cxt中的统计信息:

ReadBuffer_common
   bufHdr = BufferAlloc(....);
   if (found) {
        u_sess->instr_cxt.pg_buffer_usage->shared_blks_hit++;
   } else {
        u_sess->instr_cxt.pg_buffer_usage->shared_blks_read++;
   }

    3.  explain执行计划结束时,再拿到u_sess->instr_cxt统计信息,减去步骤1保存的初始信息,作为此sql的实际命中缓存数据保存到planstate->instrument中,代码流程如下所示:

InstrStopNode
    BufferUsageAccumDiff(&instr->bufusage, u_sess->instr_cxt.pg_buffer_usage, &instr->bufusage_start);
        dst->shared_blks_hit += add->shared_blks_hit - sub->shared_blks_hit;  // 统计此单条sql的缓存命中率,并且保存到PlanState->instr中

   4. explain从planstate中读取到缓存的命中信息并显示。

ExplainNode
  show_buffers(es, es->str, planstate->instrument, false, -1, -1, NULL);
      usage = &instrument->bufusage
          show_buffers_info4
              appendStringInfo(infostr, " hit=%ld", usage->shared_blks_hit);
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值