使用 sqlalchemy 加速插入 Sybase 中的临时表

Posted

技术标签:

【中文标题】使用 sqlalchemy 加速插入 Sybase 中的临时表【英文标题】:Speeding up insert into temp table in Sybase using sqlalchemy 【发布时间】:2020-09-10 08:41:45 【问题描述】:

在插入 sybase 临时表时性能极差 - 仅 1000 行大约需要 10 秒。 1000 行需要 46 秒,10000 行需要几分钟。我将有大约 100k 行。 有什么办法可以加快这个插入速度吗?可能是 Sybase 中的临时表配置不正确 - 如果是这样,我需要向我的 DBA 询问有关配置的什么信息?

Code :
    engine = get_connection(db_constants.DB_RISK)
    data = []
    for i in range(1, 1000, 1):
        values = ['AL' + str(i)]
        data.append(values)
    with engine.connect() as conn:
        conn.execute("CREATE TABLE " + tmp_table_name + "(alias_id varchar(255));")
        start = time.time()
        for i in range(0, len(data), 1000):
            loop_start = time.time()
            with conn.begin():
                stmt = "INSERT INTO #TMP (alias_id) VALUES (?)"
                conn.execute(stmt, data[i:i + 1000])
            loop_end = time.time()
            print("batch " + str(i) + " time elapsed : " + str(loop_end - loop_start))
        end = time.time()
        print("total time elapsed : " + str(end - start))

【问题讨论】:

哪个 Sybase RDBMS(ASE?SQLAnywhere?IQ?Advantage?)和版本? 自适应服务器企业版 谁对此投了反对票,为什么? 【参考方案1】:

假设这是 Sybase ASE ...并且不知道 OP 迄今为止执行了哪些故障排除和 P&T ...一些观察、cmets 和建议:

注意:其中大多数(全部?)将适用于任何产生中到大量数据库写入活动的程序。

延迟在哪里?

让您的 DBA 在您运行流程时监控等待事件;等待事件应该能够提供有关延迟发生位置的详细信息……在解析/编译期间? IO等待?等待客户端的数据服务器(即网络和/或客户端/应用程序延迟?)

语句缓存

优化器必须解析并可能编译这些 INSERT 语句中的每一个。

如果这是 ASE 15+ 并且正在编译每个 INSERT,这可能需要很长时间。在这种情况下,通常最好确保数据服务器已配置为支持语句缓存(禁用语句 #2 到 #N 的编译阶段)。

为语句缓存配置数据服务器意味着 1) 为“语句缓存大小”分配一些内存和 2) 将“启用文字自动参数”设置为 1。

批处理 DML 语句

每个已完成的事务都需要将更改的日志记录刷新到磁盘,然后才能将事务视为“完成”。可以通过将多个写入命令(例如,INSERT)分组到一个事务中来减少(日志的)写入磁盘的次数,这将导致日志写入延迟,直到发出“提交事务”。

虽然 ASE 15+ 应该为 tempdb 活动延迟日志写入,但将单个 DML 语句分组到事务中通常是一种好习惯。

不清楚(对我来说)您是否正在使用任何类型的事务管理,所以我建议实施一些事务管理,例如,将内部循环包装在“begin tran”和“commit tran”对中。

外部输出可能很慢

任何生成输出的程序......无论是控制台还是文件......通常会由于生成所述输出而导致性能下降(如果输出要发送到“慢”磁盘上的文件,则更是如此)。即使将大量输出转储到控制台也会大大减慢速度,因为操作系统必须不断重绘控制台(将所有行向上移动一行,在底部添加新行,重复)。

如果我正确阅读了您的代码,您将在每次插入后生成 print 语句;所以我们谈论的是 100K print 声明,是吗?有很多 IO 请求被发送到文件或控制台。

我希望在启用和不启用 print 语句(在 INSERT 之后)的情况下运行一些计时测试,看看这是否会(显着)增加您的整体运行时间。

注意:我知道,我知道,我知道......这听起来有点傻,但是......我已经看到一些进程通过限制/禁用来加速 1x-2x 数量级输出到控制台窗口。尝试在没有 INSERT 和打印的情况下运行程序……在控制台上滚动 100K 行需要多长时间?将 100K 行打印到输出/日志文件需要多长时间?

批量插入

与批量加载功能相比,单独的 INSERT 总是相对较慢。 ASE 具有(相对)快速批量数据加载的内置功能。在操作系统级别有“bcp”程序。对于编程语言(例如,python?),相关的(Sybase/ASE)库应该有一个批量插入/复制模块。

我想调查一下您的 python/Sybase/ASE 库是否有某种批量加载模块,然后考虑使用它来执行 100K INSERT。

【讨论】:

这至少不能回答我的问题 - 我们正在谈论 1000 行和 3 个打印语句的 46 秒。是的,正如你所看到的,我正在批处理,使用事务,executemany。 我不使用 python,所以我不知道,从提供的代码来看,如果您使用的是事务管理;也许我误读了内部循环 re: print 语句的开始/结束?至于答案的其余部分...您没有提供任何信息来暗示延迟发生的位置...您是否验证过您正在使用语句缓存?你看过批量插入功能吗?我添加了另一条评论,让您的 DBA 帮助您处理等待事件(即,在哪里发生延迟?);是否愿意提供有关您迄今为止执行的故障排除/P&T 的任何/更多详细信息? 好的,在这种情况下,您能否提供我在使用编程接口将长度为 25 个字符或更少字符的字符串插入 Sybase 本地临时表时所期望的数字。上面的 python 代码使用批量插入 - 它意味着高性能,这让我感到惊讶。 您询问了预期的数字; (高速)编程插入应该能够模拟 bcp 进程的输入速率,所以......您可以通过运行 bcp 测试来衡量插入速率应该是多少来获得自己的数字;至于 python vs ASE ......你还没有(还)提供任何明确指向 python 或 ASE 问题的信息;在您查看所有可能的情况之前,您只是在猜测问题所在;但是,嘿,你知道你在做什么,祝你好运

以上是关于使用 sqlalchemy 加速插入 Sybase 中的临时表的主要内容,如果未能解决你的问题,请参考以下文章

Sybase插入一个空格代替空字符串''

如何使用 SQLAlchemy 插入数据

无法从 sqlalchemy 插入到 mysql

使用核心 SQLAlchemy 插入和更新

尝试使用 SQLAlchemy 将数据插入雪花数据库表

使用 SQLAlchemy 和 Pandas 插入数据 - Python