大UPDATE [...] SELECT FROM导致并行UPDATE / DELETE死亡

时间:2013-02-16 21:06:38

标签: mysql select locking sql-update table-locking

我试图通过例子来解释我的问题。我有一个长期运行的声明,如

UPDATE <table_A>
INNER JOIN <table_B> ON [...]
LEFT JOIN <table_C> ON [...]
LEFT JOIN <table_D> ON [...]
LEFT JOIN <table_E> ON [...]
SET <table_A>.<col_A>=X
WHERE <table_A>.<col_A>=Y AND COALESCE(<table_C>.<id>,<table_D>.<id>,<table_E>.<id> IS NULL

此语句在大表上运行(其中两个表每行包含700多万行)。更新运行3-5分钟。在另一个会话中,以高并发性完成

UPDATE <table_C> SET <col_A>=Z WHERE <id> IN ([...])

DELETE FROM <table_C> WHERE <id> IN ([...])

当大UPDATE运行时,这些并发UPDATEDELETES会在一到两分钟后死锁,并发生锁定等待超时或死锁。所有JOIN列都已编制索引(标准索引)。 我已经尝试过了

SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
[BIG UPDATE];
SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ;

但这没有用。 <table_A>上的数据一致性并不那么重要(如果它包含<table_C> ... <table_E>中不存在的行,则没有问题。最重要的是,正在处理UPDATE ... DELETE上的小型<table_C> / <table_E>

1 个答案:

答案 0 :(得分:0)

由于在实时数据库上运行这么大的更新通常是一个坏主意,我建议你打破你的大更新。

这不是最优化的方法,但我相信你会设法自己优化它。

循环运行:

  1. SELECT Id, ColA FROM TableA ORDER BY Id DESC LIMIT 10 OFFSET (iteration)*10
  2. 第二个循环,从tableA.colA=Y的前一个结果中取出行 2.1。 SELECT Id FROM TableB WHERE ID=id_from_current_iteration
    2.2。 SELECT Id FROM TableC WHERE ID=id_from_current_iteration
    2.3如果先前的两个查询都返回null,则转到下一步,否则继续下一次迭代 2.4 UPDATE TableA SET ColA=X WHERE ID=id_from_current_iteration
  3. 换句话说 - 避免加入 这将花费比单次更新更长的时间,但它会起作用 优化它的第一步是批处理查询。