不知不觉第50篇了,昨天在文章里(https://mp.weixin.qq.com/s/AzBGzYhGxYjSf7Sptj55lQ)学到一个追踪源码执行情况的利器 —— Dtrace,本篇记录下实验和笔记。
学习以来一直有一个疑惑,如何将pg中执行的SQL语句和源码对应起来?回顾下之前学到的gdb调试方法,看看适用场景,以及不足。
常用调试方法
但是,如果是业务任意执行的一条语句、出现了某些怪异的现象(例如原文是加长字段长度后其统计信息被删除),如何能知道它究竟调用了pg中的哪些函数?而哪些函数是不符合我们预期的?Dtrace就能解决这个问题。
DTrace叫动态追踪(Dynamic Tracing),本身是源于Solaris系统的,无法在Linux中运行 。因为非常好用,有了Linux移植版,名SystemTap。SystemTap 也定义了一种类似的脚本语言,方便用户根据需要自由扩展。更多简介可以参考:https://blog.csdn.net/Hehuyi_In/article/details/108910781
我Oracle Linux 7的虚拟机自带了这个工具,如果没有,可以安装以下包
yum -y install systemtap systemtap-runtime
执行hello world测试命令
stap -e 'probe begin{printf("Hello, World"); exit();}'
上面那些提示对测试没什么影响,可以不管它。
如果不能输出Hello, World,则需要根据提示装一些kernel相关的包,注意必须跟操作系统的版本是一致的,不能直接yum安装最新版。
postgresql源码学习(一)—— 源码编译安装与gdb调试入门_Hehuyi_In的博客-CSDN博客_postgresql 源码调试
准备完终于可以开始测了,就以原文的例子,看看加长字段长度会调用什么函数。
vi function.c
脚本内容,process中的路径自行替换,function中的*代表输出所有函数(因为不知道具体有哪些,可以利用通配符缩小范围,例如*Start*)
probe process("/data/postgres/base/14.0/bin/postgres").function("*") {
printf("%s: %s\n", execname(), ppfunc());
}
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;
注意这个工具启动需要一定时间,所以不要一执行完脚本立刻执行对应SQL,会抓漏或者抓不到数据,可以等下面的提示出来了再开始执行。
stap function.c > mylog.txt
红色的提示可以忽略,实际已经装了这个包,并不影响使用,WARNING的信息虽然多,但也不影响使用。
4. 执行加长字段语句
alter table t alter COLUMN info type varchar(20);
这里发现需要另开一个会话才能抓到,直接在原先会话执行一直是些空闲等待的函数
再开一个窗口,mylog.txt中有输出后退出脚本,否则会记录很多无用信息。
按原文搜一下statistic相关函数,发现有了
cat mylog.txt | sort | uniq | grep -i statistic
再看看日志中的内容
定位到函数后,就回到了熟悉的内容,gdb也好vscode也好,可以根据函数名调试和搜索它了。
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);
}
另外看了下会调用该函数的文件
点开看了看,大概有以下函数(操作)会删除统计信息:
/*
* 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