PostgreSQL
 sql >> Cơ Sở Dữ Liệu >  >> RDS >> PostgreSQL

Làm cách nào tôi có thể đảm bảo rằng một chế độ xem cụ thể hóa luôn được cập nhật?

Tôi sẽ cần gọi REFRESH MATERIALIZED VIEW trên mỗi thay đổi đối với các bảng có liên quan, phải không?

Có, bản thân PostgreSQL sẽ không bao giờ tự động gọi nó, bạn cần làm theo cách nào đó.

Tôi nên làm như thế nào để thực hiện việc này?

Nhiều cách để đạt được điều này. Trước khi đưa ra một số ví dụ, hãy nhớ rằng REFRESH MATERIALIZED VIEW lệnh không chặn chế độ xem trong chế độ AccessExclusive, vì vậy trong khi nó đang hoạt động, bạn thậm chí không thể thực hiện SELECT trên bàn.

Mặc dù, nếu bạn đang ở phiên bản 9.4 hoặc mới hơn, bạn có thể cung cấp cho nó CONCURRENTLY tùy chọn:

REFRESH MATERIALIZED VIEW CONCURRENTLY my_mv;

Điều này sẽ có được ExclusiveLock và sẽ không chặn SELECT truy vấn, nhưng có thể có chi phí lớn hơn (phụ thuộc vào lượng dữ liệu đã thay đổi, nếu một vài hàng đã thay đổi thì có thể nhanh hơn). Mặc dù bạn vẫn không thể chạy hai REFRESH các lệnh đồng thời.

Làm mới theo cách thủ công

Đó là một lựa chọn để xem xét. Đặc biệt trong các trường hợp tải dữ liệu hoặc cập nhật hàng loạt (ví dụ:một hệ thống chỉ tải hàng tấn thông tin / dữ liệu sau một khoảng thời gian dài), thông thường sẽ có các hoạt động ở cuối để sửa đổi hoặc xử lý dữ liệu, vì vậy bạn có thể đơn giản bao gồm một REFRESH hoạt động cuối cùng của nó.

Lập lịch hoạt động LÀM MỚI

Tùy chọn đầu tiên và được sử dụng rộng rãi là sử dụng một số hệ thống lập lịch để gọi làm mới, ví dụ:bạn có thể định cấu hình tương tự trong cron job:

*/30 * * * * psql -d your_database -c "REFRESH MATERIALIZED VIEW CONCURRENTLY my_mv"

Và sau đó, chế độ xem cụ thể hóa của bạn sẽ được làm mới sau mỗi 30 phút.

Cân nhắc

Tùy chọn này thực sự tốt, đặc biệt với CONCURRENTLY , nhưng chỉ khi bạn có thể chấp nhận dữ liệu luôn không được cập nhật 100%. Hãy ghi nhớ rằng ngay cả khi có hoặc không có CONCURRENTLY , REFRESH lệnh cần phải chạy toàn bộ truy vấn, vì vậy bạn phải dành thời gian cần thiết để chạy truy vấn bên trong trước khi xem xét thời gian lập lịch cho REFRESH .

Làm mới bằng trình kích hoạt

Một tùy chọn khác là gọi REFRESH MATERIALIZED VIEW trong một chức năng kích hoạt, như thế này:

CREATE OR REPLACE FUNCTION tg_refresh_my_mv()
RETURNS trigger LANGUAGE plpgsql AS $$
BEGIN
    REFRESH MATERIALIZED VIEW CONCURRENTLY my_mv;
    RETURN NULL;
END;
$$;

Sau đó, trong bất kỳ bảng nào liên quan đến các thay đổi trên chế độ xem, bạn thực hiện:

CREATE TRIGGER tg_refresh_my_mv AFTER INSERT OR UPDATE OR DELETE
ON table_name
FOR EACH STATEMENT EXECUTE PROCEDURE tg_refresh_my_mv();

Cân nhắc

Nó có một số cạm bẫy quan trọng đối với hiệu suất và tính đồng thời:

  1. Mọi thao tác CHÈN / CẬP NHẬT / XÓA sẽ phải thực hiện truy vấn (có thể chậm nếu bạn đang xem xét MV);
  2. Ngay cả với CONCURRENTLY , một REFRESH vẫn chặn một cái khác, vì vậy mọi CHÈN / CẬP NHẬT / XÓA trên các bảng liên quan sẽ được tuần tự hóa.

Tình huống duy nhất tôi có thể nghĩ rằng đó là một ý kiến ​​hay là nếu những thay đổi đó thực sự hiếm.

Làm mới bằng LISTEN / NOTIFY

Vấn đề với phương án trước là nó không đồng bộ và áp đặt chi phí lớn cho mỗi hoạt động. Để cải thiện điều đó, bạn có thể sử dụng trình kích hoạt như trước đây, nhưng trình kích hoạt chỉ gọi một NOTIFY hoạt động:

CREATE OR REPLACE FUNCTION tg_refresh_my_mv()
RETURNS trigger LANGUAGE plpgsql AS $$
BEGIN
    NOTIFY refresh_mv, 'my_mv';
    RETURN NULL;
END;
$$;

Vì vậy, bạn có thể tạo một ứng dụng duy trì kết nối và sử dụng LISTEN hoạt động để xác định nhu cầu gọi REFRESH . Một dự án tuyệt vời mà bạn có thể sử dụng để kiểm tra điều này là pgsidekick, với dự án này, bạn có thể sử dụng shell script để thực hiện LISTEN , vì vậy bạn có thể lên lịch cho REFRESH như:

pglisten --listen=refresh_mv --print0 | xargs -0 -n1 -I? psql -d your_database -c "REFRESH MATERIALIZED VIEW CONCURRENTLY ?;"

Hoặc sử dụng pglater (cũng bên trong pgsidekick ) để đảm bảo bạn không gọi REFRESH rất thường xuyên. Ví dụ:bạn có thể sử dụng trình kích hoạt sau để làm cho nó REFRESH , nhưng trong vòng 1 phút (60 giây):

CREATE OR REPLACE FUNCTION tg_refresh_my_mv()
RETURNS trigger LANGUAGE plpgsql AS $$
BEGIN
    NOTIFY refresh_mv, '60 REFRESH MATERIALIZED VIEW CONCURRENLTY my_mv';
    RETURN NULL;
END;
$$;

Vì vậy, nó sẽ không gọi REFRESH cách nhau chưa đầy 60 giây và cả khi bạn NOTIFY nhiều lần trong vòng chưa đầy 60 giây, REFRESH sẽ chỉ được kích hoạt một lần.

Cân nhắc

Là tùy chọn cron, tùy chọn này cũng chỉ tốt nếu bạn có thể sử dụng với một ít dữ liệu cũ, nhưng điều này có lợi thế là REFRESH chỉ được gọi khi thực sự cần thiết, vì vậy bạn có ít chi phí hơn và dữ liệu cũng được cập nhật gần hơn khi cần thiết.

OBS:Tôi chưa thực sự thử các mã và ví dụ, vì vậy nếu ai đó tìm thấy lỗi, đánh máy hoặc thử nó và hoạt động (hoặc không), vui lòng cho tôi biết.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Truyền kiểu dữ liệu postgres

  2. Chèn dữ liệu và đặt khóa ngoại với Postgres

  3. Làm thế nào để chuyển đổi Unix epoch sang một dấu thời gian

  4. Django duy nhất cùng nhau ràng buộc thất bại?

  5. Khôi phục tệp sao lưu postgres bằng dòng lệnh?