【问题标题】:Postgres Performance Tips Loading in billions of rowsPostgres 性能提示加载数十亿行
【发布时间】:2011-06-25 12:37:57
【问题描述】:

我正在进行一个项目,该项目涉及尝试从价值 70GB 的 xml 文档中获取大量信息并将其加载到关系数据库(在本例中为 postgres)我目前正在使用 python 脚本和 psycopg2 来执行此操作插入和诸如此类。我发现随着某些表中的行数增加。 (其中最大的行数约为 500 万行)脚本(插入)的速度已经慢到爬行。以前需要几分钟的事情现在需要大约一个小时。

我能做些什么来加快这个速度?我在这个任务中使用 python 和 psycopg2 有错吗?我可以对数据库做些什么来加快这个过程。我觉得我正在以完全错误的方式处理这件事。

【问题讨论】:

    标签: python database-design postgresql psycopg2


    【解决方案1】:

    我会查看回滚日志。如果你在一笔交易中这样做,它们一定会变得相当大。

    如果是这种情况,也许您可​​以尝试提交较小的事务批处理大小。将其分成更小的记录块(1K、10K、100K 等),看看是否有帮助。

    【讨论】:

    • PostgreSQL 有 write-ahead 日志,其作用与其他数据库中的回滚日志相同。
    【解决方案2】:

    wal_buffers 和 checkpoint_segments 的设置是什么?对于大型交易,您必须调整一些设置。检查manual

    同样考虑PostgreSQL 9.0 High Performance 这本书,为了获得高性能,除了数据库配置之外,还有很多需要调整的地方。

    【讨论】:

    • 将 wal_buffers 和 checkpoint_segments 设置得太低不会导致问题随着表大小的增长而急剧恶化。这可能会有所帮助,但可能不会解决缩放问题。谢谢你的书插件。
    【解决方案3】:

    考虑到这个过程在以前是相当有效的,只是现在当数据集增长时它减慢了我的猜测是它的索引。您可以尝试在导入之前删除表上的索引,并在完成后重新创建它们。这应该会加快速度。

    【讨论】:

    • 我目前在表中没有任何索引。这也适用于外键和主键约束吗?
    • 是的,它们也是键。但是,删除它们可能需要更改您的 SQL 语句。
    • 如果你有一个主键,你就有一个索引,不管你知道与否。
    【解决方案4】:

    我会尝试使用 COPY 而不是插入。这就是备份工具用于快速加载的原因。

    检查此表中的所有外键是否在目标表上都有相应的索引。或者更好 - 在复制之前暂时删除它们并在之后重新创建。

    将 checkpoint_segments 从默认的 3(这意味着 3*16MB=48MB)增加到更高的数字 - 例如尝试 32 (512MB)。确保您有足够的空间来存储这么多额外数据。

    如果您有能力在系统崩溃或电源故障的情况下从头开始重新创建或恢复数据库集群,那么您可以使用“-F”选项启动 Postgres,这将启用操作系统写入缓存。

    【讨论】:

      【解决方案5】:
      【解决方案6】:

      在文档的Populating a Database 部分中有关于此主题的提示列表。您也可以使用Tuning Your PostgreSQL Server 中的提示来加快一般性能。

      检查外键的开销可能会随着表大小的增加而增加,这会变得更糟,因为您一次加载一条记录。如果您要加载 70GB 的数据,在加载期间删除外键,然后在导入时重建它们会快得多。如果您使用单个 INSERT 语句,则尤其如此。改用 COPY 也不能保证改进,因为挂起的触发队列是如何管理的——第一个文档链接中讨论了那里的问题。

      从 psql 提示符中,您可以找到强制执行外键的约束的名称,然后使用该名称删除它,如下所示:

      \d tablename
      ALTER TABLE tablename DROP CONSTRAINT constraint_name;
      

      加载完成后,您可以使用以下方式将其放回:

      ALTER TABLE tablename ADD CONSTRAINT constraint_name FOREIGN KEY (other_table) REFERENCES other_table (join_column);
      

      找出用于还原的确切语法的一个有用技巧是在您的数据库上执行 pg_dump --schema-only。其中的转储将向您展示如何重新创建您现在拥有的结构。

      【讨论】:

        【解决方案7】:

        前 5 百万行没什么,插入的差异不应该改变是 100k 还是 1 百万; 1-2 个索引不会减慢它的速度(如果填充因子设置为 70-90,考虑到每个主要导入是 table 的 1/10)。

        带有 PSYCOPG2 的 python 非常快。 一个小技巧,你可以使用数据库扩展 XML2 来读取/处理数据

        来自的小例子 https://dba.stackexchange.com/questions/8172/sql-to-read-xml-from-file-into-postgresql-database

        duffymo 是对的,尝试以 10000 个插入块的形式提交(仅在最后或每次插入之后提交非常昂贵) 如果您进行大量删除和更新,autovacuum 可能会变得臃肿,您可以在开始时为某些表临时关闭它。根据您的服务器可用资源设置 work_mem 和 maintenance_work_mem ... 对于插入,增加 wal_buffers,(9.0 和更高版本,默认设置为自动 -1)如果你使用版本 8 postgresql,你应该手动增加它 cud 还关闭 fsync 并测试 wal_sync_method(如果发生突然的电源故障或硬件崩溃,请谨慎更改这可能会使您的数据库崩溃不安全)

        尝试删除外键、禁用触发器或设置触发器不运行/跳过执行的条件;

        对插入、强制转换变量使用准备好的语句

        你反刍尝试将数据插入到未记录的表中以临时保存数据

        插入是否具有来自子查询、函数等的 where 条件或值?

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2020-04-26
          • 1970-01-01
          • 2016-01-26
          • 2019-04-17
          • 1970-01-01
          • 1970-01-01
          • 2021-12-18
          • 2020-04-18
          相关资源
          最近更新 更多