【发布时间】:2018-02-07 19:18:02
【问题描述】:
本质上,对于给定的@user,我们需要删除没有关联t3 记录的T1 记录。虽然不是必需,但最好删除没有T3 连接的T2 记录。
这是被推送到生产环境的代码。显然,这很棒,因为它通过了单元测试(哈哈!)...除了它在生产中导致数百万行锁定,导致服务器 500 死锁(Mysql2::Error: Deadlock found when trying to get lock; try restarting transaction ) 当多个用户同时点击DELETE 查询时。 是的,索引已经到位:
T1.where(user_id: @user.id, enabled: true)
.joins('LEFT JOIN t2 ON t2.t1_id = t1.id')
.joins('LEFT JOIN t3 ON t3.id = t2.t3_id')
.where('t3.id IS NULL').delete_all
生成的 SQL:
DELETE FROM `t1`
WHERE `t1`.`id` IN
(SELECT id FROM
(SELECT `t1`.`id` FROM `t1`
LEFT JOIN t2 ON t2.t1_id = t1.id
LEFT JOIN t3 ON t3.id = t2.t3_id
WHERE `t1`.`user_id` = 65987
AND `t1`.`enabled` = 1
AND (t2.id IS NULL)
) __active_record_temp
);
我知道这是生成的 SQL 的唯一原因是它包含在 Server 500 死锁错误中。 在测试时,我似乎无法在控制台中显示 delete_all 查询。 我能够获取查询输出并将其转换为带有解释的 SELECT,它显示了最外层的选择扫描数百万行(我相信这意味着DELETE 操作的行锁数量相同。)最里面的查询只扫描 27 行。
问题:
- 根据 Rails 中的 ActiveRecord 连接值,从一个或多个表中删除记录的最佳方法是什么?
- 我们必须在 Rails 中查看/测试 SQL 输出以确保我不会面临性能不佳和死锁的风险?
更新:情节变厚...添加当前关联
class User < ActiveRecord::Base
has_many :T1s
has_many :T2s
class T1 < ActiveRecord::Base
belongs_to :user
class T2Custom < ActiveRecord::Base
self.table_name = "t2"
has_many :T3s, :foreign_key => :t2_id
class T3 < ActiveRecord::Base
belongs_to :T2, foreign_key: "t2_id"
belongs_to :T1
【问题讨论】:
标签: mysql ruby-on-rails ruby-on-rails-4 activerecord innodb