2013-02-16 52 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