Lấy ngày sửa đổi cuối cùng của bảng cơ sở dữ liệu PostgreSQL


35

Tôi đang cố gắng nhận được khi bảng của tôi được sửa đổi bằng cách kiểm tra ngày sửa đổi tệp của nó như được mô tả trong câu trả lời này . Nhưng kết quả không phải lúc nào cũng đúng. Ngày sửa đổi tệp cập nhật trong vài phút sau khi tôi cập nhật bảng của mình. Là hành vi đúng? PostgreQuery có lưu trữ các sửa đổi bảng trong một số bộ đệm và sau đó xóa nó vào ổ cứng không?

Vì vậy, làm thế nào để tôi có được ngày sửa đổi cuối cùng chính xác của một bảng (giả sử rằng sửa đổi chân không tự động cũng ổn)?

Tôi sử dụng PostgreSQL 9.2 trong Linux Centos 6.2 x64.


4
Tôi không nghĩ rằng thời gian sửa đổi tập tin là đáng tin cậy. Nó cũng có thể thay đổi do autovacuum. Cách đáng tin cậy duy nhất là lưu trữ dấu thời gian sửa đổi trong bảng của bạn, được duy trì bởi một bộ kích hoạt.
a_horse_with_no_name

Một ý tưởng sẽ là thông tin được lưu trữ trong các tệp WAL được ghi vào tệp dữ liệu một thời gian (ngắn hơn hoặc dài hơn) sau khi thực hiện giao dịch. Nếu bạn muốn, bạn có thể gọi đây là bộ đệm :) Nếu không, tôi thứ hai những gì @a_horse_with_no_name đã nói.
dezso

Câu trả lời:


35

Không có hồ sơ đáng tin cậy, có thẩm quyền về thời gian sửa đổi cuối cùng của bảng. Sử dụng relfilenode là sai vì rất nhiều lý do:

  • Các bài viết ban đầu được ghi vào nhật ký đầu ghi (WAL), sau đó lười biếng vào heap (các tệp bảng). Khi bản ghi đã ở WAL, PG không vội viết nó vào heap và nó thậm chí có thể không được ghi cho đến khi điểm kiểm tra hệ thống tiếp theo;

  • Các bảng lớn hơn có nhiều nhánh, bạn phải kiểm tra tất cả các nhánh và chọn dấu thời gian mới nhất;

  • Một đơn giản SELECTcó thể tạo ra hoạt động ghi vào bảng bên dưới do cài đặt gợi ý bit;

  • autovaccum và bảo trì khác không thay đổi dữ liệu hiển thị của người dùng vẫn sửa đổi các tệp quan hệ;

  • một số hoạt động, như vaccum full, sẽ thay thế relfilenode. Nó có thể không phải là nơi bạn mong đợi nếu bạn đang cố gắng nhìn vào nó đồng thời mà không có một khóa thích hợp.

Một vài lựa chọn

Nếu bạn không cần độ tin cậy, bạn có thể sử dụng thông tin trong pg_stat_databasepg_stat_all_tables. Chúng có thể cung cấp cho bạn thời gian đặt lại thống kê cuối cùng và thống kê hoạt động kể từ lần đặt lại thống kê cuối cùng. Nó không cho bạn biết khi nào hoạt động gần đây nhất, chỉ có điều đó là từ lần đặt lại thống kê cuối cùng và không có thông tin nào về những gì đã xảy ra trước khi thống kê lại. Vì vậy, nó có giới hạn, nhưng nó đã ở đó.

Một tùy chọn để thực hiện nó một cách đáng tin cậy là sử dụng trình kích hoạt để cập nhật bảng chứa thời gian được sửa đổi lần cuối cho mỗi bảng. Hãy lưu ý rằng làm như vậy sẽ tuần tự hóa tất cả ghi vào bảng , phá hủy đồng thời. Nó cũng sẽ thêm một chút chi phí hợp lý cho mỗi giao dịch. Tôi không khuyên bạn nên nó.

Một thay thế ít tệ hại hơn là sử dụng LISTENNOTIFY. Có một quy trình trình nền bên ngoài kết nối với PostgreSQL và LISTENcho các sự kiện. Sử dụng các ON INSERT OR UPDATE OR DELETEkích hoạt để gửi NOTIFYs khi một bảng thay đổi, với bảng oid là tải trọng thông báo. Chúng được gửi khi giao dịch cam kết. Trình nền của bạn có thể tích lũy các thông báo thay đổi và lười biếng viết chúng trở lại một bảng trong cơ sở dữ liệu. Nếu hệ thống gặp sự cố, bạn sẽ mất bản ghi các sửa đổi gần đây nhất, nhưng không sao, bạn chỉ coi tất cả các bảng là vừa được sửa đổi nếu bạn khởi động sau sự cố.

Để tránh những vấn đề tồi tệ nhất xảy ra, thay vào đó, bạn có thể ghi lại dấu thời gian thay đổi bằng cách sử dụng trình before insert or update or delete or truncate on tablename for each statement executekích hoạt, được khái quát hóa để lấy mối quan hệ oid làm tham số. Điều này sẽ chèn một (relation_oid, timestamp)cặp vào bảng ghi nhật ký thay đổi. Sau đó, bạn có một quy trình trợ giúp trên một kết nối riêng hoặc được gọi theo định kỳ bởi ứng dụng của bạn, tổng hợp bảng đó cho thông tin mới nhất, hợp nhất nó vào một bảng tóm tắt các thay đổi gần đây nhất và cắt bớt bảng nhật ký. Ưu điểm duy nhất của phương pháp này so với phương pháp lắng nghe / thông báo là nó không bị mất thông tin về sự cố - nhưng nó thậm chí còn kém hiệu quả hơn.

Một cách khác có thể là để viết một hàm mở rộng C sử dụng (ví dụ) ProcessUtility_hook, ExecutorRun_hook, vv để thay đổi bảng bẫy và số liệu thống kê cập nhật một cách lười biếng. Tôi đã không nhìn thấy điều này sẽ thực tế như thế nào; hãy xem các tùy chọn _hook khác nhau trong các nguồn.

Cách tốt nhất là vá mã thống kê để ghi lại thông tin này và gửi một bản vá cho PostgreQuery để đưa vào lõi. Đừng chỉ bắt đầu bằng cách viết mã; nêu ý tưởng của bạn về những kẻ tấn công một khi bạn nghĩ về nó đủ để có một cách được xác định rõ ràng để thực hiện nó (tức là bắt đầu bằng cách đọc mã, đừng chỉ đăng câu hỏi "làm thế nào để tôi ..."). Có thể tốt hơn khi thêm thời gian cập nhật lần cuối vào pg_stat_..., nhưng bạn phải thuyết phục cộng đồng rằng nó đáng để chi trả hoặc cung cấp cách để làm cho nó được theo dõi tùy chọn - và bạn phải viết mã để giữ số liệu thống kê và gửi một bản vá , bởi vì chỉ có ai đó muốn tính năng này sẽ bận tâm với điều đó.

Làm thế nào tôi làm điều đó

Nếu tôi phải làm điều này và không có thời gian để viết một bản vá để thực hiện đúng cách, có lẽ tôi sẽ sử dụng phương pháp nghe / thông báo đã nêu ở trên.

Cập nhật cho dấu thời gian cam kết PostgreSQL 9.5

Cập nhật : PostgreSQL 9.5 có dấu thời gian cam kết . Nếu bạn đã bật chúng trong postgresql.confquá khứ (và cũng đã làm như vậy trong quá khứ), bạn có thể kiểm tra dấu thời gian cam kết cho hàng với mức lớn nhất xminđể xấp xỉ thời gian sửa đổi cuối cùng. Đó chỉ là một xấp xỉ bởi vì nếu các hàng gần đây nhất đã bị xóa thì chúng sẽ không được tính.

Ngoài ra, các bản ghi dấu thời gian cam kết chỉ được lưu giữ trong một thời gian giới hạn. Vì vậy, nếu bạn muốn biết khi nào một bảng không được sửa đổi nhiều được sửa đổi, câu trả lời sẽ có hiệu quả là "dunno, một thời gian trước".


17

PostgreQuery 9.5 cho phép chúng tôi theo dõi cam kết sửa đổi lần cuối.

  1. Kiểm tra cam kết theo dõi được bật hoặc tắt bằng truy vấn sau

    show track_commit_timestamp;
  2. Nếu nó trả về "BẬT", hãy chuyển sang bước 3, sửa đổi postgresql.conf

    cd /etc/postgresql/9.5/main/
    vi postgresql.conf

    Thay đổi

    track_commit_timestamp = off

    đến

    track_commit_timestamp = on

    Khởi động lại hệ thống

    Lặp lại bước 1.

  3. Sử dụng truy vấn sau để theo dõi cam kết cuối cùng

    SELECT pg_xact_commit_timestamp(xmin), * FROM  YOUR_TABLE_NAME;
    
    SELECT pg_xact_commit_timestamp(xmin), * FROM YOUR_TABLE_NAME where COLUMN_NAME=VALUE;

1
Bạn không phải khởi động lại hệ thống ở bước 2. chỉ cần khởi động lại quy trình. ví dụ sudo service postgresql restart.
ijoseph

3

Có, điều này có thể được dự kiến ​​hành xử - dữ liệu về thay đổi được lưu trữ vào nhật ký giao dịch ngay lập tức. Các tệp dữ liệu có thể được cập nhật với độ trễ checkpoint_timeout (mặc định là 5 phút). Postgres không giữ vĩnh viễn bất cứ lúc nào bạn yêu cầu.


Tôi không chắc tôi hiểu làm thế nào điều này trả lời câu hỏi. Có, dữ liệu được lưu trữ vào nhật ký giao dịch, nhưng điều đó không có nghĩa là người ta có thể dễ dàng có được thời gian sửa đổi cho một bảng cụ thể ( nếu nội dung đó vẫn còn trong nhật ký, người ta có thể phân tích nhật ký, nhưng mọi thứ sẽ được phát lại Mau).
Charles Duffy

chắc chắn, bạn có thể nhận được tất cả các thông tin cần thiết từ nhật ký, nhưng các câu hỏi được chuyển đến mtime của các tệp dữ liệu - việc thực hiện các tệp dữ liệu có thể khá ngẫu nhiên - vài giây - vài phút (tối đa 1 giờ) sau khi cam kết.
Pavel Stehule

Nỗ lực của chính OP là thông qua việc xem xét các tập tin, nhưng mục đích thực sự của họ rõ ràng là có được một bảng thời gian. Nhưng vâng, tôi hiểu bạn đến từ đâu (giải thích tại sao những gì họ đang làm không hoạt động) bây giờ.
Charles Duffy

2

Tôi có yêu cầu gần như tương tự để duy trì bộ đệm của một số bảng trên ứng dụng khách. Tôi nói gần như vậy , vì tôi thực sự không cần biết thời điểm sửa đổi lần cuối, mà chỉ để phát hiện xem có gì đó đã thay đổi kể từ lần cuối bộ đệm được đồng bộ hóa hay không.

Đây là cách tiếp cận của tôi:

Miễn là bạn có cột id(PK), created_on(dấu thời gian chèn) và updated_on(dấu thời gian cập nhật, có thể là cột NULL) trên mỗi bảng, bạn có thể

SELECT id,greatest(created_on,updated_on) FROM %s ORDER BY greatest(created_on,updated_on) DESC LIMIT 1;

Nếu bạn kết hợp số này và thêm số lượng hàng, bạn có thể tạo thẻ phiên bản trông giống như vậy count:id#timestampvà nó sẽ là duy nhất cho mọi phiên bản dữ liệu trong bảng.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.