在实时数据库上更新之前删除索引

Removing indexes before Update on a live Database

我们正在 Heroku 上开发实时 Postgres 数据库。我们需要使用正则表达式替换多个字符串来更新大约 500 万行,这意味着总共执行大约 1 亿次更新。

我们正在以这种方式更新它:(使用 psycopg2)

for element in list:
    cursor.execute("Update table set text = regexp_replace(text, %s, 'NewWord', 'gi') where date >= '2017-12-31';", [element])

数据库已上线并链接到我们的 Django 网站,我们需要在 3 天内推出一项新功能,要求对数据库进行此更新。 Postgres Guides 说如果我们删除索引会快得多,但是删除外键索引可能会停止我们的一些 django 功能并使网站瘫痪。即便如此,我们还是可以在周末休息一到两天,但仅此而已。

所以 :

  1. 是否可以安全地假设通过删除索引,1 亿 更新可以在一天内完成吗?
  2. 如果是这样,我们是否也应该删除主节点 关键指标?
  3. 如果没有,我们假设有多少时间会出现类似的情况 更新将在不删除索引的情况下进行?
  1. 一个小时内可以完成1亿次更新。 (如果行大小不是太大)
  2. 没有。主键不受更新文本字段的影响,所以你应该不用管它
  3. 更新所需的时间与有无索引大致相同(如果受影响的文本字段上没有索引)

您的查询(为简单起见,我删除了参数化,并将 {table,date,text} 替换为 {ztable,zdate,ztext},因为它是关键字):

Update ztable
set ztext = regexp_replace(ztext, 'Oldword', 'NewWord', 'gi')
where zdate >= '2017-12-31';

可以通过在 where 子句中添加一个额外的条件来大大加快速度,例如:

Update ztable
set ztext = regexp_replace(ztext, 'Oldword', 'NewWord', 'gi')
where zdate >= '2017-12-31'
AND ztext LIKE '%Oldword%'
;

如果更新实际上对行没有任何作用,这将避免创建额外的行版本。 (一次更新花费 1 read-I/O + 大约 3 I/Os 如果行确实被更改,受影响的磁盘块的数量取决于稀疏性和行大小)

额外注意:如果ztext列有索引:扔掉;它可能没用。 也许可以通过删除前端中的循环并将所有逻辑放在 UPDATE 中来获得额外的性能。