postgresql源码学习(50)—— 小白学习Dtrace追踪源码函数调用

       不知不觉第50篇了,昨天在文章里(https://mp.weixin.qq.com/s/AzBGzYhGxYjSf7Sptj55lQ)学到一个追踪源码执行情况的利器 —— Dtrace,本篇记录下实验和笔记。

一、 解决痛点

      学习以来一直有一个疑惑,如何将pg中执行的SQL语句和源码对应起来?回顾下之前学到的gdb调试方法,看看适用场景,以及不足。

常用调试方法

  • 已知函数名:gdb调试。包括很常用的一些语句例如checkpoint,对应函数名网上都能搜到
  • 慢查询卡在某个特定函数:可以gdb跟踪进程然后查看调用栈
  • 有报错信息:根据报错文本在源码中搜索

       但是,如果是业务任意执行的一条语句、出现了某些怪异的现象(例如原文是加长字段长度后其统计信息被删除),如何能知道它究竟调用了pg中的哪些函数?而哪些函数是不符合我们预期的?Dtrace就能解决这个问题。

二、 准备工作

       DTrace叫动态追踪(Dynamic Tracing),本身是源于Solaris系统的,无法在Linux中运行 。因为非常好用,有了Linux移植版,名SystemTap。SystemTap 也定义了一种类似的脚本语言,方便用户根据需要自由扩展。更多简介可以参考:https://blog.csdn.net/Hehuyi_In/article/details/108910781

1. 安装SystemTap

我Oracle Linux 7的虚拟机自带了这个工具,如果没有,可以安装以下包

yum -y install systemtap systemtap-runtime

执行hello world测试命令

stap -e 'probe begin{printf("Hello, World"); exit();}'

postgresql源码学习(50)—— 小白学习Dtrace追踪源码函数调用_第1张图片

上面那些提示对测试没什么影响,可以不管它。

       如果不能输出Hello, World,则需要根据提示装一些kernel相关的包,注意必须跟操作系统的版本是一致的,不能直接yum安装最新版。

2. 使用--enable-dtrace选项编译安装pg

postgresql源码学习(一)—— 源码编译安装与gdb调试入门_Hehuyi_In的博客-CSDN博客_postgresql 源码调试

三、 开始测试

准备完终于可以开始测了,就以原文的例子,看看加长字段长度会调用什么函数。

1. Systemtap脚本准备

vi function.c

      脚本内容,process中的路径自行替换,function中的*代表输出所有函数(因为不知道具体有哪些,可以利用通配符缩小范围,例如*Start*)

probe process("/data/postgres/base/14.0/bin/postgres").function("*") {
        printf("%s: %s\n", execname(), ppfunc());
}

2. 创建测试表

create table t(id int,info varchar(10));
insert into t select n,left(md5(random()::text),10) from generate_series(1,1000) as n;
analyze t;

postgresql源码学习(50)—— 小白学习Dtrace追踪源码函数调用_第2张图片

3. 执行Systemtap脚本

       注意这个工具启动需要一定时间,所以不要一执行完脚本立刻执行对应SQL,会抓漏或者抓不到数据,可以等下面的提示出来了再开始执行。

stap function.c > mylog.txt

postgresql源码学习(50)—— 小白学习Dtrace追踪源码函数调用_第3张图片

       红色的提示可以忽略,实际已经装了这个包,并不影响使用,WARNING的信息虽然多,但也不影响使用。

4. 执行加长字段语句

alter table t alter COLUMN info type varchar(20);

这里发现需要另开一个会话才能抓到,直接在原先会话执行一直是些空闲等待的函数

postgresql源码学习(50)—— 小白学习Dtrace追踪源码函数调用_第4张图片

5. 观察输出结果

再开一个窗口,mylog.txt中有输出后退出脚本,否则会记录很多无用信息。

按原文搜一下statistic相关函数,发现有了

cat mylog.txt | sort | uniq | grep -i statistic

再看看日志中的内容

postgresql源码学习(50)—— 小白学习Dtrace追踪源码函数调用_第5张图片

四、 源码学习

定位到函数后,就回到了熟悉的内容,gdb也好vscode也好,可以根据函数名调试和搜索它了。

postgresql源码学习(50)—— 小白学习Dtrace追踪源码函数调用_第6张图片

postgresql源码学习(50)—— 小白学习Dtrace追踪源码函数调用_第7张图片

       RemoveStatistics函数用于为单表或单列删除pg_statistic系统表中对应的记录。如果attnum为零(未指定列),删除该表的所有记录;如果指定了列,则删除该列的记录。

/*
 * RemoveStatistics --- remove entries in pg_statistic for a rel or column
 *
 * If attnum is zero, remove all entries for rel; else remove only the one(s)
 * for that column.
 */
void
RemoveStatistics(Oid relid, AttrNumber attnum)
{
    Relation    pgstatistic;
    SysScanDesc scan;
    ScanKeyData key[2];
    int         nkeys;
    HeapTuple   tuple;

    pgstatistic = table_open(StatisticRelationId, RowExclusiveLock);

    ScanKeyInit(&key[0],
                Anum_pg_statistic_starelid,
                BTEqualStrategyNumber, F_OIDEQ,
                ObjectIdGetDatum(relid));

    if (attnum == 0)
        nkeys = 1;
    else
    {
        ScanKeyInit(&key[1],
                    Anum_pg_statistic_staattnum,
                    BTEqualStrategyNumber, F_INT2EQ,
                    Int16GetDatum(attnum));
        nkeys = 2;
    }

    scan = systable_beginscan(pgstatistic, StatisticRelidAttnumInhIndexId, true,
                              NULL, nkeys, key);

    /* we must loop even when attnum != 0, in case of inherited stats */
    while (HeapTupleIsValid(tuple = systable_getnext(scan)))
        CatalogTupleDelete(pgstatistic, &tuple->t_self);

    systable_endscan(scan);

    table_close(pgstatistic, RowExclusiveLock);
}

另外看了下会调用该函数的文件

postgresql源码学习(50)—— 小白学习Dtrace追踪源码函数调用_第8张图片

点开看了看,大概有以下函数(操作)会删除统计信息:

  • heap_drop_with_catalog - removes specified relation from catalogs,删表
  • RemoveAttributeById - This is the guts of ALTER TABLE DROP COLUMN,删列
  • index_drop - 删索引
  • ATExecAlterColumnType - ALTER COLUMN .. SET DATA TYPE,改字段类型,注释为
   /*
     * Drop any pg_statistic entry for the column, since it's now wrong type
     */
    RemoveStatistics(RelationGetRelid(rel), attnum);

 这方法感觉有点傻,应该有更方便能看到函数调用信息的工具?不过暂时没搜到,留待以后吧~

参考

PostgreSQL修改列类型又掉坑了!

使用动态追踪Dtrace分析问题

https://gist.github.com/alexandrnikitin/7fd095371e8c105f6cb9ab7f87664547

PostgreSQL数据库统计信息——统计信息系统表_肥叔菌的博客-CSDN博客_postgresql 表统计信息

《Linux性能优化实战》笔记(24)—— 动态追踪 DTrace_Hehuyi_In的博客-CSDN博客_dtrace linux

postgresql源码学习(一)—— 源码编译安装与gdb调试入门_Hehuyi_In的博客-CSDN博客_postgresql 源码调试

源码研究方法论----PG篇.mp4--吕海波_哔哩哔哩_bilibili

你可能感兴趣的:(源码学习,PostgreSQL,性能,postgresql,源码学习,统计信息,Dtrace,Systemtap)