Postgresql

PostgreSQL:需要定期輪換一個視圖中提到的大表

  • September 6, 2022

我有一個看法:

CREATE OR REPLACE VIEW v_Foo0 AS
SELECT lotsofstuff
 FROM Bar INNER JOIN LotsOfOtherJoins

CREATE TABLE old_Foo AS SELECT * FROM v_Foo LIMIT 0;

CREATE OR REPLACE VIEW v_Foo AS
SELECT * FROM v_Foo0
WHERE stuff NOT IN (SELECT stuff FROM old_Foo);

CREATE TABLE Foo AS SELECT * FROM v_Foo LIMIT 0;

然後我有DML,它在一個過程中定期執行,正常的方式可能是這樣的:

BEGIN TRANSACTION;

INSERT INTO old_Foo SELECT * FROM Foo;

TRUNCATE TABLE Foo;
INSERT INTO Foo SELECT * FROM v_Foo;

...

INSERT INTO Foo 
SELECT * FROM old_Foo
WHERE (stuff) NOT IN (SELECT stuff FROM old_Foo)

TRUNCATE TABLE old_Foo;

...

COMMIT;

關鍵是 Foo 是巨大的,並且正在逐步重建,基於 Foo 中尚未出現的新內容。然後發生了許多其他事情,然後 old_Foo 中尚未在重建的 Foo 中的任何內容都將被複製到重建的 Foo 中,然後可以刪除 old_Foo 。

但是有一個不必要的複制操作,其中數以百萬計的行被打亂,只是為了保留舊的東西。我寧願將 Foo 重命名為 old_Foo 然後重建新的 Foo:

BEGIN TRANSACTION;

ALTER TABLE Foo RENAME TO old_Foo;

CREATE TABLE Foo AS SELECT * FROM v_Foo LIMIT 0;
INSERT INTO Foo SELECT * FROM v_Foo;

...

INSERT INTO Foo 
SELECT * FROM old_Foo
WHERE (stuff) NOT IN (SELECT stuff FROM old_Foo)

DROP TABLE old_Foo;

...

COMMIT;

問題是,我不能重命名 Foo 也不能刪除 old_Foo 因為它們在 v_Foo 視圖中被引用。而且我希望該視圖在執行時引用任何稱為Foo 的表,而不是在定義視圖時緊貼稱為 Foo 的表。

有這個視圖的原因是它是一個多屏頁面完整查詢,我不想把它放到一些每次都重新定義的過程中。我只想要那裡的那個視圖,當重建這個 Foo 的時間到來時,我希望它做它的事情。

在現實世界中,有很多像 Foo 這樣的表,我只是不想像在一個瘋狂的 5000 行程序中那樣一遍又一遍地重新定義這些視圖。

一直在考慮是否可以使用分區表,但是一旦更改分區鍵,我就必須執行 UPDATE,這將轉換為將數百萬行複製到 old_Foo 分區中。所以什麼也得不到。

簡單而無需重新考慮所有事情並假設您所做的一切是做到這一點的唯一方法是:

  • 放下視圖
  • 放下桌子
  • 重新創建視圖

另一種做事的方法是創建另一個 foo 表,對其進行所有更改(插入/刪除),然後刪除視圖/重新創建視圖以指向該新表,以便您現在可以刪除 foo 表並將您的表重命名為 foo。

刪除或創建視圖不需要很長時間。

我仍然建議在同一個事務中執行所有查詢,以便您可以輕鬆回滾,並且連接到數據庫的人將始終看到表 foo 和視圖 v_foo。

我贊同 Arkhena 的回答——刪除並重新創建一個視圖沒什麼大不了的。

如果你想避免這種情況,你可以求助於一個函式並以此為基礎:

CREATE FUNCTION view_fun() RETURNS TABLE (...)
  LANGUAGE sql AS
$$SELECT ... FROM foo WHERE ...$$;

CREATE VIEW foo_view AS SELECT * FROM view_fun();

由於這樣的函式將不依賴於foo,因此您可以重命名表,並且由於該函式不儲存已解析的查詢,因此它將始終使用目前呼叫的表foo

引用自:https://dba.stackexchange.com/questions/316487