to_sql写pg性能问题跟踪解决

1. 问题描述

有部分数据,从原来写mysql实例,改成写pg实例,用pandas.DataFrame.to_sql方法。

期间发现,同样的数据写mysql和pg,耗时差异相当大
10万+数据量,mysql 1-3秒,pg 2-3分钟
40万+数据量,mysql 5-8秒,pg 9-10分钟

写mysql和pg代码都差不多,写pg代码示例如下

engine = create_engine('postgresql://use:password@host:port/database')

connect = engine.connect()

df.to_sql(table, engine, index=False, if_exists='append')

2. 问题分析

2.1 机器差异

同样的数据,基本相同结构的表,写性能相差那么大,第一直觉是mysql和pg实例差异。

跟运维同事要到pg实例的监控,pg性能完全没有问题,cpu、io、mem负载都很低,不超过10%,没有大的波动,机器性能完全没压榨出来。

2.2 表结构及数据问题

既然机器不是问题,那可能是表结构或者数据特征,对mysql友好,对pg不友好。尽管可能性很小,但还是要尝试一下。

  • 将简单的表结构,条数不变,批量写pg性能提升不大
  • 将数据类型改成简单类型,过滤处理空值数据,条数不变,批量写pg性能提升不大

测试证明,不是表结构问题,也不是数据问题,很可能就是to_sql本身的问题。

2.3 to_sql方法分析

pandas.to_sql方法提供了很多参数,参考了to_sql的优化方法,做了些尝试,没什么效果。

也有人总结说to_sql方法写pg有问题,建议利用pg的copy from特性,解决批量写pg的性能瓶颈。

3. 优化方法

3.1 to_sql方法调参

调整chunksize,设置dtype参数,等等,耗时变化不大。

但有文章指出,to_sql方法稳定,不会对数据库内存和IO有压力。

3.2 insert拼接

将40万条数据分批写入,每批10000条,拼接insert sql语句,耗时缩短1半多,还是有明显提升。

但这种方法太笨拙,需要把DataFrame数据遍历处理,不通用,性能提升有限。

3.3 pg的copy from特性

有人分享了pg的优化方法,利用StringIO和pg的copy from特征,将DataFrame先用to_csv到string io,然后从string io copy到pg。

示例具体代码如下,没有用copy_from方法,而是copy_expert

import io

def write_to_pg(engine, df, table):
        string_io_data = io.StringIO()
        df.to_csv(string_io_data, sep='|', index=False)
        string_io_data.seek(0)
        with engine.connect() as connection:
            with connection.connection.cursor() as cursor:
                copy_cmd = "COPY {} FROM STDIN HEADER DELIMITER '|' CSV".format(table)
                cursor.copy_expert(copy_cmd, string_io_data)
            connection.connection.commit()

优化前后效果对比:

数据量mysql(to_sql)pg(to_sql)pg(copy_from)
10万1-3秒2-3分钟1-2秒
40万5-8秒9-10分钟3-4秒

copy_expert直接将IO缓冲区数据复制到pg目标表,内存性能提升明显,但对数据库IO有一定压力。

另外,DataFrame的columns必须是和目标表的columns顺序一致,不然会导致数据列错位。也可以用copy_from方法,调用的时候才指定columns。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值