[Greenplum]解决greenplum数据库truncate table或drop table很慢的问题

 

问题描述:    

    在solaris10上使用greenplum3.3.6,当数据文件很多的,truncate table和drop table很慢,常常这样一个操作需要3分钟到十几分钟。这个问题只到greenplum4.0都存在。

原因分析:

    对于PostgreSQL数据库来说每个表都是由一个或几个文件组成的,文件由一个数据组成,如名称为:123468,文件大小不能超过一个设定值,目前是1G,如果表的内容超过了1G,g内容写到下一个加了”.数字"的文件中,如123468.1,当123468.1写满了,再放到123468.2文件中,依此类推。当greenplum在truncate table或drop table时,会把表对应的文件删除,删除的方式是,先删除123468这个文件,然后遍历这个目录下的所有文件,看这个目录下的每一个文件名前面是否是123468.n的格式(n为1,2,3...),如果是,再把这个文件删除。随着greenplum数据库的变大,数据目录下有几十万个文件甚至 到达百万个文件,于是遍历目录就会很慢,这就是导致的greenplum3.3.X truncate table和drop table很慢的原因。

解决方法:

    与greenplum公司联系过,他们说升级到greenplum4.1,这个问题就解决了,但由于一般的greenplum数据库都比较大,而最新版本greenplum4.1还有一些bug,升级风险很大。所以这个问题,于是只有自己想办法解决这个问题。

    由于是遍历目录慢,能否让系统跳过这个步骤。方法是,我写一个动态库fixgptrunc.so,这个动态库重载列目录的函数readdir_r,然后设置环境变量LD_PRELOAD_64:

export LD_PRELOAD_64=/home/gpadmin/fixgptrunc/fixgptrunc.so

    这样当,postgres进程起来时,当调用遍历目录的函数readdir_r时,就会调用我写的这个动态库中的readdir_r函数,而当我的函数 readdir_r,看到postgres是遍历数据目录时,就跳过。这样这个性能问题就解决了。

这里大家可能有几个疑问:

    1. 如果跳过了,那么那些带后缀的123468.1、123468.2文件系统就不会删除了,这怎么办? 我的解决方法是,也重载unlink函数,我的unlink在当删除123468文件时,就自动去把123468.1和123468.2这样的文件都删除 掉。

    2. 如果postgres进程不是在做truncate table和drop table时,去调用readdir_r函数时,直接跳过,这样是否会使用这些正常的需要调readdir_r的操作也会出现找不到文件的错误? 这个问题的解决方法是我的unlink函数会检查调用unlink函数的父函数是否是mdunlink函数,mdunlink函数是 PostgreSQL的一个删除表文件的函数,一般只会在做drop table或truncate table时才会调用mdunlink函数,除此之外的正常调用,则不会调用这个mdunlink函数,这样就不会有这个问题了。如果父函数是 mdunlink,才跳过,否则按正常流程走。


程序使用方法:

   使用gmake生成fixgptrunc.so文件,

   然后把这个文件拷贝到master和各个segment结点,我测试的时候,放在/home/gpadmin/fixgptrunc/这个目录下:

然后在.bashrc文件中增加环境变量:

export LD_PRELOAD_64=/home/gpadmin/fixgptrunc/fixgptrunc.so

export FIX_GP_TRUNC_DEBUG=1

   设置了环境变量FIX_GP_TRUNC_DEBUG=1,则会在/tmp文件目录下生成一个log文件:fixgptrunc.log,便于调 试。

然后重启greenplum后,再做truncate table或drop table就应该很快了。


源代码见附件。