自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

解鎖七大技巧,避免你的 Postgres 掛掉

數(shù)據(jù)庫 PostgreSQL
如果這些事務同時運行,它們很可能會互相卡住,永遠無法完成。Postgres 會在一秒鐘左右后識別出這種情況,并取消其中一個事務,讓另一個事務完成。出現(xiàn)這種情況時,你應該檢查一下自己的應用程序,看看能否讓事務始終按照相同的順序進行。

1.永遠不要添加帶默認值的列

從 PostgreSQL 11 開始,添加帶默認值的列不再重寫表。本博文中的其他提示仍然有效!

PostgreSQL 的黃金法則是:在生產(chǎn)中向表添加列時,千萬不要指定默認值。

添加列會對表加上鎖,從而阻塞讀寫。如果添加的列有默認值,PostgreSQL 會重寫整個表,為每一行填寫默認值,這對大型表來說可能需要數(shù)小時。在此期間,所有查詢都會阻塞,數(shù)據(jù)庫將不可用。

不要這樣做:

-- 阻塞讀寫一直到完全重寫(以小時計)
ALTER TABLE items ADD COLUMN last_update timestamptz DEFAULT now();

改用這個方法:

-- 阻塞查詢,更新,插入,刪除直到 catalog 被更新 (毫秒計)
ALTER TABLE items ADD COLUMN last_update timestamptz;
-- 查詢,插入可以執(zhí)行,一些更新和刪除在重寫表時,會被阻塞
UPDATE items SET last_update = now();

或者更好的辦法是,通過小批量更新來避免長時間阻塞更新和刪除,例如:

do {
  numRowsUpdated = executeUpdate(
    "UPDATE items SET last_update = ? " +
    "WHERE ctid IN (SELECT ctid FROM items WHERE last_update IS NULL LIMIT 5000)",
    now);
} while (numRowsUpdate > 0);

這樣,您就可以在盡量不影響用戶的情況下添加和填充新列。

譯者按,在 Bytebase 中對應的是這條 SQL 審核規(guī)則:

圖片圖片

2.當心鎖隊列,使用 lock timeouts (鎖超時)

在 PostgreSQL 中,每個鎖都有一個隊列。如果事務 B 試圖獲取一個已經(jīng)被事務 A 持有的有沖突的鎖,那么事務 B 將會在鎖隊列中等待。現(xiàn)在有趣的是:如果另一個事務 C 加入,它不僅需要檢查與事務 A 的沖突,還需要檢查與事務 B 以及鎖隊列中其他所有事務的沖突。

這意味著即使你的 DDL 命令可以非??焖俚剡\行,它也可能在隊列中等待很長時間,因為需要等待其他查詢完成,并且在它之后啟動的查詢將會被它阻塞。

如果表上可能長時間運行 SELECT 查詢,就不要這樣做:

ALTER TABLE items ADD COLUMN last_update timestamptz;

而應該這樣做:

SET lock_timeout TO '2s'
ALTER TABLE items ADD COLUMN last_update timestamptz;

通過設置 lock_timeout 參數(shù),如果 DDL 命令因為等待鎖而阻塞查詢超過 2 秒,該命令將會失敗。這樣做的缺點是 ALTER TABLE 可能不會成功,但可以稍后再試。在開始 DDL 命令之前,建議先查詢 pg_stat_activity,查看是否有長時間運行的查詢。

3.CONCURRENTLY (并行地)創(chuàng)建索引

PostgreSQL 的另一條黃金法則是:始終并行地創(chuàng)建索引。

在大型數(shù)據(jù)集上創(chuàng)建索引可能需要數(shù)小時甚至數(shù)天,而常規(guī)的 CREATE INDEX 命令會在命令執(zhí)行期間阻止所有寫入操作。雖然不會阻塞 SELECT,但這仍然很糟糕,而且還有更好的方法:CREATE INDEX CONCURRENTLY。

不要這樣做:

-- 阻塞所有寫
CREATE INDEX items_value_idx ON items USING GIN (value jsonb_path_ops);

而應這樣做:

-- 只阻塞其他 DDL 操作
CREATE INDEX CONCURRENTLY items_value_idx ON items USING GIN (value jsonb_path_ops);

并發(fā)地創(chuàng)建索引有一個缺點。如果出了問題,它不會回滾,而是留下一個未完成(invalid)的索引。如果出現(xiàn)這種情況,不用擔心,只需運行 DROP INDEX CONCURRENTLY items_value_idx,然后再嘗試創(chuàng)建一次即可。

譯者按,在 Bytebase 中對應的是這條 SQL 審核規(guī)則:

圖片圖片

4.盡可能晚地獲取高級別的鎖

當需要運行命令獲取表上高級別的鎖時,應盡量在事務的較晚階段執(zhí)行,以允許查詢盡可能長時間地進行。

例如,如果要完全替換表的內(nèi)容。不要這樣做:

BEGIN;
-- 阻塞讀寫:
TRUNCATE items;
-- 長時間操作:
\COPY items FROM 'newdata.csv' WITH CSV 
COMMIT;

取而代之的是,將數(shù)據(jù)加載到新表中,然后替換舊表:

BEGIN;
CREATE TABLE items_new (LIKE items INCLUDING ALL);
-- 長時間操作:
\COPY items_new FROM 'newdata.csv' WITH CSV
-- 阻塞讀寫:
DROP TABLE items;
ALTER TABLE items_new RENAME TO items;
COMMIT;

有一個問題,我們沒有從一開始就阻止寫入,因此當我們刪除舊的 items 表時,它可能已經(jīng)發(fā)生了變化。為了防止出現(xiàn)這種情況,我們可以顯式鎖表,阻止寫入,但不阻止讀取:

BEGIN;
LOCK items IN EXCLUSIVE MODE;
...

有時,自己動手加鎖更為保險。

5.添加主鍵并盡量減少加鎖

在表中添加主鍵通常是個好主意。例如,當你想使用邏輯復制遷移數(shù)據(jù)庫時。

Postgres 讓使用 ALTER TABLE 創(chuàng)建主鍵變得非常簡單,但在為主鍵建立索引的過程中(如果表很大,可能需要很長時間),所有查詢都會被阻塞。

ALTER TABLE items ADD PRIMARY KEY (id); -- 長時間阻塞查詢

幸運的是,你可以先使用 CREATE UNIQUE INDEX CONCURRENTLY 完成所有繁重的工作,然后使用唯一索引作為主鍵,這是一種快速操作。

CREATE UNIQUE INDEX CONCURRENTLY items_pk ON items (id); -- 會很長,但不會阻塞查詢
ALTER TABLE items ADD CONSTRAINT items_pk PRIMARY KEY USING INDEX items_pk;  -- 會阻塞查詢,但很快

通過將創(chuàng)建主鍵分解為兩個步驟,幾乎不會對用戶造成影響。

6.永遠不要使用 VACUUM FULL

Postgres 的用戶體驗有時會讓人吃驚。雖然 VACUUM FULL 聽起來像是清除數(shù)據(jù)庫灰塵的命令,但更合適的命令應該是:請凍結(jié)我的數(shù)據(jù)庫數(shù)小時。

PLEASE FREEZE MY DATABASE FOR HOURS;
VACUUM FULL
VACUUM FULL

雖然你應該調(diào)整 AUTO VACUUM 設置并使用索引來加快查詢速度,但你可能有時需要運行 VACUUM,而不是 VACUUM FULL。

7.通過重排指令避免死鎖

如果你已經(jīng)使用 PostgreSQL 有一段時間了,你很可能見過類似的錯誤:

ERROR:  deadlock detected
DETAIL:  Process 13661 waits for ShareLock on transaction 45942; blocked by process 13483.
Process 13483 waits for ShareLock on transaction 45937; blocked by process 13661.

當并發(fā)事務以不同順序獲取相同鎖時,就會出現(xiàn)這種情況。例如,一個事務發(fā)出以下命令。

BEGIN;
UPDATE items SET counter = counter + 1 WHERE key = 'hello'; -- 在 hello 上加鎖
UPDATE items SET counter = counter + 1 WHERE key = 'world'; -- 一邊阻塞 hello,一邊等著 world
END;

與此同時,另一個事務可能會發(fā)出相同的命令,但順序不同。

BEGIN
UPDATE items SET counter = counter + 1 WHERE key = 'world'; -- 在 world 上加鎖
UPDATE items SET counter = counter + 1 WHERE key = 'hello';  -- 一邊阻塞 world,一邊等著 hello
END;

如果這些事務同時運行,它們很可能會互相卡住,永遠無法完成。Postgres 會在一秒鐘左右后識別出這種情況,并取消其中一個事務,讓另一個事務完成。出現(xiàn)這種情況時,你應該檢查一下自己的應用程序,看看能否讓事務始終按照相同的順序進行。如果兩個事務都先修改 hello,再修改 world,那么第一個事務就會在搶到其他鎖之前阻塞第二個事務的 hello 鎖。

責任編輯:武曉燕 來源: Bytebase
相關推薦

2011-07-05 14:19:02

云備份云計算

2023-02-21 14:55:40

React開發(fā)技巧

2010-07-20 10:48:56

Perl文件操作

2021-09-17 13:17:56

Spring 模塊開發(fā)

2009-03-17 08:33:22

Windows7節(jié)省開支

2013-07-22 15:36:48

谷歌秘密項目

2018-02-28 10:11:22

UPS電源預防

2021-02-19 23:42:18

高考物聯(lián)網(wǎng)農(nóng)業(yè)

2010-05-24 13:04:53

jQueryJavaScript

2015-07-08 08:51:11

SDN

2020-12-18 10:35:27

IT技術領導者

2020-12-22 09:55:55

IT首席信息官CIO

2022-05-23 08:09:42

物聯(lián)網(wǎng)IOT

2018-04-11 14:13:29

物聯(lián)網(wǎng)信息技術互聯(lián)網(wǎng)

2015-08-05 16:21:23

開源社區(qū)

2024-10-29 08:00:00

PAMPAM部署IT

2024-09-04 08:31:01

語言模型設計

2014-11-07 16:57:21

程序員

2016-06-06 09:49:15

2023-06-27 07:31:02

動畫庫React參數(shù)
點贊
收藏

51CTO技術棧公眾號