sql - PostgreSQL、外键、插入速度和 Django

标签 sql django postgresql insert foreign-keys

几天前,我在使用非常标准的 Django 设置时遇到了意外的性能问题。对于即将推出的功能,我们必须每小时重新生成一个表,其中包含大约 10 万行数据,磁盘上有 9M,根据 pgAdmin 有 10M 索引。

问题是通过任何方法插入它们都需要很长时间,100% 磁盘繁忙时间最多需要 3 分钟。这不是您在生产站点上想要的东西。插入是否在事务中、通过普通插入、多行插入、COPY FROM 或什至 INSERT INTO t1 SELECT * FROM t2 发出都无关紧要。

在注意到这不是 Django 的错后,我进行了试错,嘿,在删除所有外键后问题消失了! INSERT INTO SELECT FROM 的执行时间不是 3 分钟,而是不到一秒的执行时间,这对于磁盘上 <= 20M 的表来说并不奇怪。 奇怪的是,PostgreSQL 仅通过使用 3 个外键就设法将插入速度降低了 180 倍。

哦,磁盘事件是纯粹的写入,因为所有内容都缓存在 RAM 中;只写入磁盘。看起来 PostgreSQL 正在非常努力地接触所引用表中的每一行,因为 3MB/sec * 180s 比这个新表在磁盘上占用的 20MB 数据要多得多。在 180 年代的情况下没有 WAL,我直接在 psql 中进行测试,在 Django 中,为 WAL 日志记录添加约 50% 的开销。尝试了@commit_on_success,同样缓慢,我什至用 psycopg2 实现了多行插入和 COPY FROM。这是另一件奇怪的事情,值(value) 10M 的插入如何生成 > 10x 16M 的日志段?

表格布局:id serial primary,一堆int32,3个外键

  • 小表,198 行,磁盘 16k
  • 大表,120 万行,59 条数据 + 磁盘上 89 MB 索引
  • 大表,220 万行,198 + 210MB

那么,我是否注定要手动删除外键或通过定义保存 bla_id x3 并跳过使用 models.ForeignKey 以非常不符合 Django 的方式使用表?我很想听听一些神奇的解毒剂/pg 设置来解决这个问题。

最佳答案

如果不必等待 IO 读取,则 100.000 FK 检查大约需要 2-5 秒。 比插入表慢得多,但比你得到的时间快得多。

检查所有外键是否已索引:

(我说的是引用列的索引,而不是引用列,明白吗?)

如果 products.category_id REFERENCES category(id),并且 category.id 上没有索引,每次需要检查 FK 时都必须扫描表。

要找出哪一个不是,请先插入 1 个 FK,然后再插入 2 个 FK...您会发现哪一个是负责的。

是的,如果您截断表,删除所有约束和索引并在批量插入后重建它们会更快。

关于sql - PostgreSQL、外键、插入速度和 Django,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1472446/

相关文章:

sql - 使用 Bigquery 删除具有 "REPEATED"模式的嵌套列

python - 如何在 django 模板中使用换行符从数据库中输出文本?

postgresql - 在 Postgresql 中,有没有办法将列的值限制为枚举?

Postgresql 9.2.1 普通用户模式与独立后端模式

django - Django 注解的数学运算

javascript - 如何使用 javascript 将来自 postgres sql 查询的值分配给前端的字段

mysql - 如何编写mysql查询以仅在foreign_key存在时插入值

mysql - SQL操作数执行单行、列

mysql - 从 00 :00:00 to 23:59:59 更改 mySQL 默认时间

python - 添加外键Django时列不存在错误