2013-02-16 50 views
1

我想通过例子来解释我的问题。我有一个长时间运行的语句像大的更新[...]从根源并行更新/删除死

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 

此声明大表运行(其中两个含有每桌7+万行)。更新运行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 S于<table_C> ... <table_E>正在处理中。

+0

这通常不是一个好主意,使活动数据库上这么大的更新。例如,您可以将您的重大更新分解为几个较小的更新。 – Anri 2013-02-16 21:11:54

+0

这对我来说是没有选择的,因为我必须知道,“product_id”必须不在任何一个表中。“#'......''。我已经尝试了你的建议,但是它们中最大的表包含了超过700万行,这足以导致lockwait超时(无论事实如果其他两个表也是'JOIN'ed) – rabudde 2013-02-16 21:22:56

+0

检查我的答案是否与你尝试过的不同。 – Anri 2013-02-16 21:49:02

回答

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如果两个以前的查询返回的空转到下一步,否则继续下一个迭代 2.4 UPDATE TableA SET ColA=X WHERE ID=id_from_current_iteration

换句话说 - 避免加入
这将花费比单次更新更长的时间,但它会起作用。
优化它的第一步是批量查询。

+0

好吧,你已经分解了'JOIN's,这不是我的意图,但应该从理论上解决问题,所以你的答案被接受。这个问题是由于我将'UPDATE'和'JOIN'结合在一起,因为它锁定了行。我已经改变了'UPDATE'以循环'id',现在以10,000步为单位。每个循环运行2-3秒,现在我的体验好多了。 – rabudde 2013-02-22 09:56:32

+0

如果您将解决方案也添加为答案,那将会很好。 – Anri 2013-02-22 11:01:52