2014-09-24 51 views
0

有一個潛在的大型更新語句可以更改表上的布爾標誌和時間戳列。如何執行不會鎖定其他查詢的更新?

此操作可能會更新表中可能有幾百萬行的幾千行。

更新操作不應該鎖定表,並且如果可能同時運行的其他查詢得到陳舊的數據,我非常樂意。

目標是以不會影響其他讀取操作的方式執行更新語句(如果可能,甚至更新)。

在這種情況下,如果讀取操作在更新語句正在處理時爲布爾標誌和時間戳列獲取不正確的值,那就好了。

postgresql是否有更新語句的任何查詢優化,我可以使用給定上述寬鬆的要求?

+2

作家不會阻止Postgres中的讀者,讀者也不會阻止作者。 Postgres將只會鎖定你更新的行,並會阻止其他會話更新它們。更新語句永遠不會鎖定整個表(除非更新所有行,但仍然可以查詢該表)否將禁止選擇語句。這就是Postgres的工作原理,沒有什麼是你需要做的。 – 2014-09-24 15:58:44

+0

@a_horse_with_no_name哦,我明白了,好奇,你知道mysql是否以同樣的方式行事? – 2014-09-24 16:34:01

+0

我認爲是的(可能會出現一些鎖升級,但我不確定。我幾乎沒有必要使用MySQL)。但我會說現代DBMS將(應該)以這種方式行事。 – 2014-09-24 17:16:22

回答

0

由於@a_horse_with_no_name筆記,一個UPDATE(或INSERTDELETE)並不妨礙在PostgreSQL的併發SELECT S,除非這些SELECT就做明確的行與FOR UPDATEFOR SHARE鎖定。

因此,您可以在更新運行時從表中繼續使用SELECTSELECT只會看到舊的值。

任何UPDATE S或DELETE s表示影響的行已經被UPDATE d將是上的行鎖阻塞直到現有UPDATE完成。但是,在這裏更新順序有一個皺紋。

如果你的大更新按順序掃描表,更新每一行,然後你做另一個小的UPDATE以其他順序掃描表來選擇要更新的行,你可以找到一個死鎖。大的更新可能會鎖定id = 1000的行,並試圖鎖定id = 1001的行。但是你的較新的小更新已經在id = 1001上有一個鎖,並試圖獲得id = 1000的鎖。他們也無法獲得他們想要的鎖,所以他們被卡住了。 PostgreSQL檢測到這個並且終止其中一個死鎖檢測錯誤的語句。有無法保證哪些聲明將被中止。

爲了緩解這種情況,我建議將您的大UPDATE分成一系列小UPDATE s,如果可能的話,每個值的範圍。這還會減少數據庫必須在表中分配的額外工作空間的數量,以存儲行的新版本,直到更新完成並可以清除舊數據。

我希望MySQL + InnoDB的行爲類似。當您執行UPDATE時,MySQL + MyISAM將鎖定表格,但您不應該使用MyISAM。