Làm thế nào tôi có thể biết khi nào một bảng MySQL được cập nhật lần cuối?


176

Trong phần chân trang của tôi, tôi muốn thêm một cái gì đó như "cập nhật lần cuối xx / xx / 200x" với ngày này là lần cuối cùng một bảng myQuery nhất định được cập nhật.

Cách tốt nhất để làm điều đó là gì? Có một chức năng để lấy lại ngày cập nhật cuối cùng? Tôi có nên truy cập vào cơ sở dữ liệu mỗi khi tôi cần giá trị này không?


Câu trả lời:


276

Trong các phiên bản sau của MySQL, bạn có thể sử dụng information_schemacơ sở dữ liệu để cho bạn biết khi nào một bảng khác được cập nhật:

SELECT UPDATE_TIME
FROM   information_schema.tables
WHERE  TABLE_SCHEMA = 'dbname'
   AND TABLE_NAME = 'tabname'

Tất nhiên điều này có nghĩa là mở một kết nối đến cơ sở dữ liệu.


Một tùy chọn thay thế sẽ là "chạm" vào một tệp cụ thể bất cứ khi nào bảng MySQL được cập nhật:

Về cập nhật cơ sở dữ liệu:

  • Mở tệp dấu thời gian của bạn trong O_RDRWchế độ
  • close nó một lần nữa

Hay cách khác

  • sử dụng touch(), tương đương với utimes()hàm của PHP , để thay đổi dấu thời gian của tệp.

Trên trang hiển thị:

  • sử dụng stat()để đọc lại thời gian sửa đổi tập tin.

9
Để biết chi tiết bao gồm các giới hạn của InnoDB, hãy xem dev.mysql.com/doc/refman/5.5/en/show-table-status.html ( show table statussử dụng information_schema.tables)
KCD

11
Cả UPDATE_TIMEphương thức và show table statusphương thức bên dưới chỉ khả dụng với công cụ MyISAM, không phải InnoDB. Mặc dù điều này được liệt kê là một lỗi , nhưng nó được đề cập trong Tài liệu tham khảo MySQL 5.5 , cũng nói rằng file_per_tablechế độ này là một chỉ số không đáng tin cậy về thời gian sửa đổi.
idoimaging

5
Một lần nữa, không hoạt động trên InnoDB vì mysql là f ** king buggy: bug.mysql.com/orms.php?id=14374
TMS

7
Đối với MySQL 5.7.2+, nó cũng hoạt động với InnoDB : "Bắt đầu với MySQL 5.7.2, UPDATE_TIME hiển thị giá trị dấu thời gian cho các CẬP NHẬT, INSERT hoặc DELETE cuối cùng được thực hiện trên các bảng InnoDB không được phân vùng. Trước đây, UPDATE_TIME hiển thị giá trị NULL cho các bảng InnoDB. "
Peter V. Mørch

2
Điều này dường như không tiếp tục khởi động lại cho tôi (trên phiên bản 5.7.11).

58

Tôi không có cơ sở dữ liệu information_schema, sử dụng phiên bản mysql 4.1.16, vì vậy trong trường hợp này bạn có thể truy vấn điều này:

SHOW TABLE STATUS FROM your_database LIKE 'your_table';

Nó sẽ trả về các cột này:

| Tên | Động cơ | Phiên bản | Hàng_format | Hàng | Average_row_length 
| Dữ liệu_length | Max_data_length | Index_length | Dữ liệu_free | Tự động đăng ký
| Tạo_time | Cập nhật_time | Kiểm tra thời gian | Đối chiếu
| Tổng kiểm tra | Tạo_options | Nhận xét |

Như bạn có thể thấy có một cột được gọi là: " Update_time " hiển thị cho bạn thời gian cập nhật cuối cùng cho your_table .


2
Nó cũng thực hiện nhanh hơn (4x) sau đó là câu lệnh CHỌN
jmav

1
Trên thực tế, hầu hết các lệnh SHOW như thế này chỉ được ánh xạ vào các truy vấn Information_schema bên trong, vì vậy câu trả lời này cung cấp chính xác dữ liệu giống như câu trả lời từ Alnitak ở trên. Và ajacian81 là chính xác - nó không hoạt động cho công cụ lưu trữ mặc định của MySQL, InnoDB.
Bill Karwin

55

Tôi ngạc nhiên không ai đề xuất theo dõi thời gian cập nhật mới nhất trên mỗi hàng:

mysql> CREATE TABLE foo (
  id INT PRIMARY KEY
  x INT,
  updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP 
                     ON UPDATE CURRENT_TIMESTAMP,
  KEY (updated_at)
);

mysql> INSERT INTO foo VALUES (1, NOW() - INTERVAL 3 DAY), (2, NOW());

mysql> SELECT * FROM foo;
+----+------+---------------------+
| id | x    | updated_at          |
+----+------+---------------------+
|  1 | NULL | 2013-08-18 03:26:28 |
|  2 | NULL | 2013-08-21 03:26:28 |
+----+------+---------------------+

mysql> UPDATE foo SET x = 1234 WHERE id = 1;

Điều này cập nhật dấu thời gian mặc dù chúng tôi đã không đề cập đến nó trong CẬP NHẬT.

mysql> SELECT * FROM foo;
+----+------+---------------------+
| id | x    | updated_at          |
+----+------+---------------------+
|  1 | 1235 | 2013-08-21 03:30:20 | <-- this row has been updated
|  2 | NULL | 2013-08-21 03:26:28 |
+----+------+---------------------+

Bây giờ bạn có thể truy vấn MAX ():

mysql> SELECT MAX(updated_at) FROM foo;
+---------------------+
| MAX(updated_at)     |
+---------------------+
| 2013-08-21 03:30:20 |
+---------------------+

Phải thừa nhận rằng điều này đòi hỏi nhiều dung lượng hơn (4 byte mỗi hàng cho TIMESTAMP).
Nhưng điều này hoạt động cho các bảng InnoDB trước phiên bản 5.7.15 của MySQL, INFORMATION_SCHEMA.TABLES.UPDATE_TIMEkhông có.


10
+1 Theo như tôi quan tâm, đây là câu trả lời đúng duy nhất cho câu hỏi này. Câu hỏi thực sự muốn biết khi nào dữ liệu liên quan được cập nhật, và không phải khi nào một bảng (không liên quan đến người dùng) có thể hoặc không thể thay đổi vì bất kỳ lý do gì.
siride

23
Nhưng nếu bạn xóa một bản ghi với thời gian cập nhật thấp hơn, MAX (update_at) sẽ không hoạt động.
Ammamon

3
@Ammamon, đúng, nếu bạn cũng cần tính đến việc xóa, giải pháp này không phản ánh điều đó. Một kích hoạt để cập nhật bảng tóm tắt có thể là giải pháp toàn diện duy nhất, nhưng điều đó sẽ tạo ra một nút cổ chai.
Bill Karwin

2
đối với hầu hết các trường hợp biết việc xóa sẽ không liên quan và nhiều aps cấp cao hơn không thực sự xóa khỏi nhiều bảng mà chỉ đơn giản là bỏ cờ cho tương đương.
Samuel Fullman

1
@Pavan, không có sự khác biệt, bạn chỉ dựa vào hành vi mặc định và ví dụ của tôi nói rõ tùy chọn này. Nhưng tùy chọn này giống hệt với hành vi mặc định.
Bill Karwin

13

Điều đơn giản nhất là kiểm tra dấu thời gian của các tệp bảng trên đĩa. Ví dụ: Bạn có thể kiểm tra trong thư mục dữ liệu của bạn

cd /var/lib/mysql/<mydatabase>
ls -lhtr *.ibd

Điều này sẽ cung cấp cho bạn danh sách tất cả các bảng với bảng khi nó được sửa đổi lần cuối cùng lần đầu tiên.


Câu trả lời thực sự tuyệt vời kể từ UPDATE_TIME là NULL cho tất cả các bảng trong trường hợp (MariaDb) của tôi
Alexander Vasiljev

tập tin ibd chỉ lưu trữ cấu trúc bảng. Theo mặc định, dữ liệu được lưu trữ trong ibdata1 nên dấu thời gian của tệp ibd sẽ không cập nhật khi dữ liệu được thay đổi trong bảng. https://dev.mysql.com/doc/refman/8.0/en/show-table-status.html
Stack Underflow

7

Để biết danh sách các thay đổi bảng gần đây, hãy sử dụng:

SELECT UPDATE_TIME, TABLE_SCHEMA, TABLE_NAME
FROM information_schema.tables
ORDER BY UPDATE_TIME DESC, TABLE_SCHEMA, TABLE_NAME

3
Tại sao tất cả của tôi UPDATE_TIMElà null? Bất kỳ ý tưởng?
Metafaniel

5
UPDATE_TIME của bạn là null vì bạn đang sử dụng InnoDB thay vì MyISAM. InnoDB nói chung là sự lựa chọn tốt hơn, nhưng nó không hỗ trợ UPDATE_TIME.
Xaraxia

5

Tôi sẽ tạo một trình kích hoạt bắt tất cả các cập nhật / chèn / xóa và viết dấu thời gian trong bảng tùy chỉnh, giống như tablename | dấu thời gian

Chỉ vì tôi không thích ý tưởng đọc trực tiếp các bảng hệ thống nội bộ của máy chủ db


1
Đây có vẻ là một giải pháp tốt cho MS SQL, vì không có UPDATE_TIMEcột như trong MySQL.
Darcy

3

Mặc dù có một câu trả lời được chấp nhận nhưng tôi không cảm thấy đó là câu trả lời đúng. Đó là cách đơn giản nhất để đạt được những gì cần thiết, nhưng ngay cả khi đã được bật trong InnoDB (thực ra các tài liệu cho bạn biết rằng bạn vẫn nên nhận NULL ...), nếu bạn đọc tài liệu MySQL , ngay cả trong phiên bản hiện tại (8.0) bằng UPDATE_TIME là không phải là lựa chọn đúng đắn, bởi vì:

Dấu thời gian không được duy trì khi máy chủ được khởi động lại hoặc khi bảng bị xóa khỏi bộ đệm từ điển dữ liệu InnoDB.

Nếu tôi hiểu chính xác (không thể xác minh nó trên máy chủ ngay bây giờ), dấu thời gian sẽ được đặt lại sau khi máy chủ khởi động lại.

Đối với các giải pháp thực tế (và, tốt, tốn kém), bạn có giải pháp của Bill Karwin với CURRENT_TIMESTAMP và tôi muốn đề xuất một khác, dựa trên các kích hoạt (tôi đang sử dụng giải pháp đó).

Bạn bắt đầu bằng cách tạo một bảng riêng (hoặc có thể bạn có một số bảng khác có thể được sử dụng cho mục đích này) sẽ hoạt động giống như một bộ lưu trữ cho các biến toàn cục (ở đây là dấu thời gian). Bạn cần lưu trữ hai trường - tên bảng (hoặc bất kỳ giá trị nào bạn muốn giữ ở đây dưới dạng id bảng) và dấu thời gian. Sau khi bạn có nó, bạn nên khởi tạo nó với id bảng này + ngày bắt đầu (NOW () là một lựa chọn tốt :)).

Bây giờ, bạn di chuyển đến các bảng bạn muốn quan sát và thêm các kích hoạt SAU KHI CHỌN / CẬP NHẬT / XÓA với quy trình này hoặc tương tự:

CREATE PROCEDURE `timestamp_update` ()
BEGIN
    UPDATE `SCHEMA_NAME`.`TIMESTAMPS_TABLE_NAME`
    SET `timestamp_column`=DATE_FORMAT(NOW(), '%Y-%m-%d %T')
    WHERE `table_name_column`='TABLE_NAME';
END

1

Phân tích cấp độ hệ điều hành:

Tìm nơi lưu trữ DB trên đĩa:

grep datadir /etc/my.cnf
datadir=/var/lib/mysql

Kiểm tra các sửa đổi gần đây nhất

cd /var/lib/mysql/{db_name}
ls -lrt

Nên làm việc trên tất cả các loại cơ sở dữ liệu.


0

Chỉ cần lấy ngày tập tin sửa đổi từ hệ thống tập tin. Trong ngôn ngữ của tôi đó là:

 tbl_updated = file.update_time(
        "C:\ProgramData\MySQL\MySQL Server 5.5\data\mydb\person.frm")

Đầu ra:

1/25/2013 06:04:10 AM

6
Trông giống như hack không di động, một cách tiêu chuẩn sẽ hoạt động ở mọi nơi sẽ tốt hơn
Tejesh Alimilli 20/03/13

0

Nếu bạn đang chạy Linux, bạn có thể sử dụng inotify để xem bảng hoặc thư mục cơ sở dữ liệu. inotify có sẵn từ PHP, node.js, perl và tôi nghi ngờ hầu hết các ngôn ngữ khác. Tất nhiên bạn phải cài đặt inotify hoặc ISP của bạn đã cài đặt nó. Rất nhiều ISP sẽ không.


2
Kiểm tra hệ thống tập tin không hữu ích nếu cơ sở dữ liệu của bạn đang chạy trên một máy chủ riêng biệt
Sam Dufel

0

Không chắc chắn nếu điều này sẽ được quan tâm. Sử dụng mysqlproxy ở giữa mysql và máy khách và sử dụng tập lệnh lua để cập nhật giá trị khóa trong memcached theo các thay đổi bảng thú vị CẬP NHẬT, XÓA, INSERT là giải pháp mà tôi đã làm gần đây. Nếu trình bao bọc hỗ trợ hook hoặc kích hoạt trong php, điều này có thể đã được phục hồi. Không ai trong số các trình bao bọc như bây giờ làm điều này.


0

tôi đã tạo một cột theo tên: update-at trong phpMyAdmin và nhận được thời gian hiện tại từ phương thức Date () trong mã của tôi (nodejs). với mỗi thay đổi trong bảng, cột này giữ thời gian thay đổi.


1
Chào mừng bạn đến với StackOverflow! Vui lòng chỉnh sửa câu trả lời của bạn để bao gồm một số mã bạn đã sử dụng, cũng như giải thích lý do tại sao bạn chọn thực hiện theo cách này. Câu hỏi này đã gần mười một tuổi và đã có một câu trả lời được chấp nhận, được đánh giá cao. Câu trả lời của bạn, không có một số mã hoặc một lời giải thích, có thể sẽ bị hạ cấp hoặc bị xóa. Chỉnh sửa nó để bao gồm những điều đó sẽ giúp chứng minh vị trí của nó trên bài đăng này.
Das_Geek

0

a) Nó sẽ hiển thị cho bạn tất cả các bảng và có ngày cập nhật mới nhất

SHOW TABLE STATUS FROM db_name;

Sau đó, bạn có thể yêu cầu thêm bảng cụ thể:

SHOW TABLE STATUS FROM db_name like 'table_name';

b) Như trong các ví dụ trên, bạn không thể sử dụng sắp xếp trên 'Update_time' nhưng sử dụng CHỌN bạn có thể:

SELECT * FROM information_schema.tables WHERE TABLE_SCHEMA='db_name' ORDER BY UPDATE_TIME DESC;

để hỏi thêm về bảng cụ thể:

SELECT * FROM information_schema.tables WHERE TABLE_SCHEMA='db_name' AND table_name='table_name' ORDER BY UPDATE_TIME DESC';

-1

Đây là những gì tôi đã làm, tôi hy vọng nó sẽ giúp.

<?php
    mysql_connect("localhost", "USER", "PASSWORD") or die(mysql_error());
    mysql_select_db("information_schema") or die(mysql_error());
    $query1 = "SELECT `UPDATE_TIME` FROM `TABLES` WHERE
        `TABLE_SCHEMA` LIKE 'DataBaseName' AND `TABLE_NAME` LIKE 'TableName'";
    $result1 = mysql_query($query1) or die(mysql_error());
    while($row = mysql_fetch_array($result1)) {
        echo "<strong>1r tr.: </strong>".$row['UPDATE_TIME'];
    }
?>

2
Tại sao bạn sẽ sử dụng như ở đây?
Kyle Buser

3
@WesleyMurch: thẻ <font> không được dùng nữa.
siride

-9

Lưu trữ truy vấn trong một biến toàn cục khi nó không có sẵn.

Tạo một trang web để buộc bộ nhớ cache được tải lại khi bạn cập nhật nó.

Thêm một cuộc gọi đến trang tải lại vào tập lệnh triển khai của bạn.


2
bạn không thể "lưu trữ" các biến giữa các yêu cầu độc lập của trang PHP mà không cần sự trợ giúp bên ngoài.
Alnitak
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.