PostgreSQL'de adım adım alternatifleştirilmiş görünümü yenileme


33

PostgreSQL'de artımlı olarak yenilenmiş bir görünümü yenilemek mümkün mü yani sadece yeni veya değiştirilmiş veriler için?

Bu tabloyu ve materyalize görünümü ele alalım:

CREATE TABLE graph (
   xaxis integer NOT NULL,
   value integer NOT NULL,
);

CREATE MATERIALIZED VIEW graph_avg AS 
SELECT xaxis, AVG(value)
FROM graph
GROUP BY xaxis

Periyodik olarak, yeni değerler eklenir graphveya mevcut bir değer güncellenir. Görünümü graph_avgyalnızca birkaç saatte bir, yalnızca güncellenmiş değerler için yenilemek istiyorum . Ancak PostgreSQL 9.3'te tüm tablo yenilenmiştir. Bu oldukça zaman alıcı. Bir sonraki 9.4 sürümü CONCURRENTgüncellemeye izin veriyor ancak yine de tüm görünümü yeniliyor. 100 milyonlarca satırla bu birkaç dakika sürer.

Güncellenen ve yeni değerleri takip etmenin ve görünümü yalnızca kısmen yenilemenin iyi bir yolu nedir?

Yanıtlar:


22

Kendi masanızı her zaman "somutlaştırılmış görünüm" olarak uygulayabilirsiniz. Daha önce yapmanız gereken MATERIALIZED VIEWde bu, Postgres 9.3'te iki şekilde de uygulanıyordu.

Örneğin, bir düz oluşturabilirsiniz VIEW:

CREATE VIEW graph_avg_view AS 
SELECT xaxis, AVG(value) AS avg_val
FROM   graph
GROUP  BY xaxis;

Ve sonucu bir kez ya da baştan başlamanız gerektiğinde bir bütün olarak gerçekleştirin:

CREATE TABLE graph_avg AS
SELECT * FROM graph_avg_view

(Ya da SELECTifadeyi doğrudan oluşturmadan kullanın VIEW.)
Ardından, kullanım durumunuzun açıklanmayan ayrıntılarına bağlı olarak, DELETE/ UPDATE/ INSERTmanüel olarak değişiklik yapabilirsiniz .

Tablonuz için aşağıdaki gibi veri değiştiren CTE'leri içeren temel bir DML deyimi :

Başka hiç kimsenin aynı anda yazmaya çalışmadığını farz etmek graph_avg(okuma sorun değil):

WITH del AS (
   DELETE FROM graph_avg t
   WHERE  NOT EXISTS (SELECT 1 FROM graph_avg_view v WHERE v.xaxis = v.xaxis);
   )
, upd AS (
   UPDATE graph_avg t
   FROM   graph_avg_view v
   WHERE  t.xaxis = v.xaxis
   AND    t.avg_val <> v.avg_val
   )
INSERT INTO graph_avg t
SELECT *
FROM   graph_avg_view v
LEFT   JOIN graph_avg t USING (xaxis)
WHERE  t.xaxis IS NULL;

Ancak bu büyük olasılıkla optimize edilmelidir.

Temel tarif:

  • Temel tablonuza timestampvarsayılan now()olarak bir sütun ekleyin . Hadi diyelim ts.
    • Güncelleştirmeleriniz varsa, geçerli zaman damgasını xaxisveya değiştiren her güncellemeyle ayarlamak için bir tetikleyici ekleyin value.
  • En son anlık görüntünüzün zaman damgasını hatırlamak için küçük bir tablo oluşturun. Diyelim ki mv:

    CREATE TABLE mv (
       tbl text PRIMARY KEY
     , ts timestamp NOT NULL DEFAULT '-infinity'
    ); -- possibly more details
  • Bu kısmi, çok noktalı virgül dizini oluşturun:

    CREATE INDEX graph_mv_latest ON graph (xaxis, value)
    WHERE  ts >= '-infinity';
  • Anlık görüntüyü mükemmel dizin kullanımıyla yenilemek için sorgularınızda belirleyici olarak son anlık görüntünün zaman damgasını kullanın .

  • İşlemin sonunda, dizini bırakın ve '-infinity'aynı zamanda tablonuza kaydettiğiniz dizin yüklemesindeki (başlangıçta ) zaman damgasını değiştiren işlem zaman damgasıyla yeniden oluşturun . Tek işlemde her şey .

  • Not kısmi indeks kapağına büyük olduğunu INSERTve UPDATEoperasyonların değil DELETE. Bunu örtbas etmek için tüm masayı düşünmelisin. Hepsi kesin gereksinimlere bağlıdır.


Gerçekleşen görüşlerin netliği ve alternatif bir cevap önerdiğiniz için teşekkür ederiz.
user4150760

13

Eşzamanlı Güncelleme (Postgres 9.4)

İstediğiniz gibi artan bir güncelleme olmasa da, Postgres 9.4 yeni bir eşzamanlı güncelleme özelliği sunar.

Dokümanı alıntılamak için…

PostgreSQL 9.4'ten önce, maddileştirilmiş bir görüntüyü yenilemek, tüm masayı kilitlemek ve bu nedenle sorgulamayı engellemek anlamına geliyordu ve bir yenileme özel kilidi elde etmek uzun zaman aldıysa (bunu bitirmek için sorgular beklerken) sonraki sorguları tutuyor. Bu şimdi CONCURRENTLY anahtar kelimesiyle azaltılabilir:

 postgres=# REFRESH MATERIALIZED VIEW CONCURRENTLY mv_data;

Ancak, maddileştirilmiş görünümde benzersiz bir endeksin bulunması gerekecektir. Materyalleşmiş görüntüyü kilitlemek yerine, bunun geçici olarak güncellenmiş bir versiyonunu yaratır, iki sürümü karşılaştırır, sonra farkı uygulamak için materyalize edilmiş görünüme karşı INSERT ve DELETE'ler uygular. Bu, sorgular güncellenirken hala maddileştirilmiş görünümü kullanabileceği anlamına gelir. Eşzamanlı olmayan biçiminden farklı olarak, tuples donmaz ve ölü tuples'i geride bırakacak olan söz konusu DELETE'ler nedeniyle VACUUMing'e ihtiyacı vardır.

Bu eşzamanlı güncelleme hala taze bir sorgu gerçekleştiriyor (artan değil). Dolayısıyla CONCURRENTLY genel hesaplama süresinden tasarruf sağlamaz, yalnızca gerçekleştirilmiş görünümünüzün güncelleme sırasında kullanılamayacağı süreyi en aza indirir.


11
Bir an yakından okuyana kadar heyecanlandım. it instead creates a temporary updated version of it...compares the two versions- Bu, geçici olarak güncellenen sürümün hala tam bir hesaplama olduğu anlamına gelir, ardından farkı mevcut görünüme uygular. Yani aslında, hala TÜM hesaplamaları yeniden yapıyorum, ancak sadece geçici tabloda.
user4150760

5
Ah, doğru, CONCURRENTLYgenel hesaplama süresinden tasarruf etmiyor, yalnızca güncelleştirilmiş görünümünüzün güncelleme sırasında kullanılamayacağı süreyi en aza indirir.
Basil Bourque
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.