【问题标题】:Deadlocks in PostgreSQL when running a simple UPDATE运行简单 UPDATE 时 PostgreSQL 中的死锁
【发布时间】:2020-03-21 11:44:02
【问题描述】:

update cities set cdb_data = NULL, updated_at = now() where cities.id = 1;

我们循环遍历城市并使用 cdb_data 作为 rails 代码的一部分更新城市,但是我们不断收到以下错误。

ActiveRecord::StatementInvalid: PG::TRDeadlockDetected: ERROR:  deadlock detected
DETAIL:  Process 26741 waits for ShareLock on transaction 2970537161; blocked by process 26818.
Process 26818 waits for ShareLock on transaction 2970537053; blocked by process 26741.
HINT:  See server log for query details.
CONTEXT:  while updating tuple (39,15) in relation "cities"
UPDATE "cities" SET "cdb_data" = $1, "updated_at" = $2 WHERE "cities"."id" = $3

更新城市对象的 Ruby 代码

    city              = City.find_or_create_by(uuid: city_data['uuid'])
    city.name         = city_data['name']
    city.state_id     = city_data['state_id']
    city.cdb_data     = city_data
    city.save

我不知道这个错误发生在哪条记录上,为什么? 即使在本地或暂存中进行生产转储,这似乎也不会发生。 任何帮助将不胜感激。

我在 heroku 上运行服务器,所以我不确定我是否能看到 postgres 日志。

【问题讨论】:

  • 您能否详细说明您是如何更新记录的?您是否正在获取多条记录、锁定它们并一一更新?需要更多详细信息。
  • 已使用更新城市的 ruby​​ 脚本更新问题
  • 我正在一个一个地抓取记录并更新记录。
  • 还是不清楚。事务在何时何地开始和提交?试着弄清楚,如果您以不同的顺序更新来自 2 个不同事务的多条记录?跨 2 个事务的交错更新可能会导致此问题。
  • 例如:Tx 1 正在按顺序更新城市 -> 1, 4, 6, 8。当 Tx 2 按顺序更新时 -> 4, 6, 8, 1。现在,Tx 1 可能会锁定记录 1,而 Tx 2 可能会锁定记录 4。所以,Tx 1 无法继续,直到Tx 2 完成。但是Tx 2 必须等待记录在1 上的锁释放,由Tx 1 持有,因此出现死锁。

标签: ruby-on-rails postgresql ruby-on-rails-5 postgresql-9.5 database-deadlocks


【解决方案1】:

两个这样的事务很容易死锁。

为避免该问题,请确保当您“循环穿过城市”时,始终以相同的顺序执行此操作,使用类似以下内容:

FOR c IN
   SELECT * FROM city
   WHERE /* whatever */
   ORDER BY city.id
LOOP
   /* perform the update */
END LOOP;

【讨论】:

    【解决方案2】:

    要查找锁定更新查询的原因,可以使用

    SELECT pg_blocking_pids(<pid of the query that is locked>);
    

    【讨论】:

      猜你喜欢
      • 2012-05-01
      • 1970-01-01
      • 1970-01-01
      • 2010-10-31
      • 1970-01-01
      • 2018-12-06
      • 2021-03-22
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多