Các trường tăng tự động của MySQL tự đặt lại


12

Chúng tôi có một bảng MySQL có trường tăng tự động được đặt là INT (11). Bảng này lưu trữ khá nhiều danh sách các công việc đang chạy trong một ứng dụng. Tại bất kỳ thời điểm nào trong suốt vòng đời của ứng dụng, bảng cũng có thể chứa hàng ngàn mục nhập hoặc hoàn toàn trống (tức là mọi thứ đã kết thúc).

Lĩnh vực này không phải là chìa khóa nước ngoài cho bất cứ điều gì khác.

Việc tăng tự động dường như tự đặt lại ngẫu nhiên về 0, mặc dù chúng tôi chưa bao giờ thực sự có thể bẫy thiết lập lại.

Vấn đề trở nên rõ ràng bởi vì chúng ta thấy trường tăng tự động lên tới 600.000 bản ghi hoặc sau đó một lúc sau đó, trường tăng tự động dường như đang chạy trong 1000 thấp.

Nó gần như là tăng tự động đặt lại nếu bảng trống.

Điều này có thể không và nếu có, làm cách nào để tắt hoặc thay đổi cách đặt lại?

Nếu không, có ai có lời giải thích tại sao nó có thể làm điều này không?

Cảm ơn!


Phiên bản nào của MySQL? Là giao dịch hoặc nhân rộng trong sử dụng?
mỏng

Câu trả lời:


26

Bộ đếm tăng tự động chỉ được lưu trữ trong bộ nhớ chính, không phải trên đĩa.

http://dev.mysql.com/doc/refman/4.1/en/innodb-auto-increment-handling.html

Vì điều này khi dịch vụ (hoặc máy chủ) khởi động lại, những điều sau đây sẽ xảy ra:

Sau khi khởi động máy chủ, lần đầu tiên chèn vào bảng t, InnoDB thực thi tương đương với câu lệnh này: CHỌN MAX (ai_col) TỪ ĐỂ CẬP NHẬT;

InnoDB tăng thêm một giá trị được lấy bởi câu lệnh và gán nó cho cột và cho bộ đếm tăng tự động cho bảng. Nếu bảng trống, InnoDB sử dụng giá trị 1.

Vì vậy, trong tiếng Anh đơn giản, sau khi dịch vụ MySQL khởi động, nó không biết giá trị tăng tự động cho bảng của bạn là gì. Vì vậy, khi bạn lần đầu tiên chèn một hàng, nó sẽ tìm giá trị tối đa của trường sử dụng tự động tăng, thêm 1 vào giá trị này và sử dụng giá trị kết quả. Nếu không có hàng, nó sẽ bắt đầu từ 1.

Đây là một vấn đề đối với chúng tôi, vì chúng tôi đang sử dụng tính năng tăng tự động của bảng và mysql để quản lý gọn gàng ID trong môi trường đa luồng, nơi người dùng được chuyển hướng đến trang web thanh toán của bên thứ ba. Vì vậy, chúng tôi phải đảm bảo ID mà bên thứ ba nhận và gửi lại cho chúng tôi là duy nhất và sẽ giữ nguyên như vậy (và tất nhiên có khả năng người dùng sẽ hủy giao dịch sau khi họ được chuyển hướng).

Vì vậy, chúng tôi đã tạo một hàng, lấy giá trị tăng tự động được tạo, xóa hàng để giữ bảng sạch và chuyển tiếp giá trị đến trang thanh toán. Cuối cùng, chúng tôi đã làm gì để khắc phục vấn đề về cách InnoDB xử lý các giá trị AI là như sau:

$query = "INSERT INTO transactions_counter () VALUES ();";
mysql_query($query);
$transactionId = mysql_insert_id();
$previousId = $transactionId - 1;
$query = "DELETE FROM transactions_counter WHERE transactionId='$previousId';";
mysql_query($query); 

Điều này luôn giữ giao dịch mới nhất được tạo dưới dạng một hàng trong bảng, mà không cần thiết làm nổ tung bảng.

Hy vọng rằng sẽ giúp bất cứ ai khác có thể gặp phải điều này.

Chỉnh sửa (2018-04-18) :

Như Finesse đã đề cập dưới đây, có vẻ như hành vi này đã được sửa đổi trong MySQL 8.0+.

https://dev.mysql.com/worklog/task/?id=6204

Từ ngữ trong worklog đó bị lỗi nhiều nhất, tuy nhiên nó xuất hiện InnoDB trong các phiên bản mới hơn hiện hỗ trợ các giá trị tự động liên tục trong các lần khởi động lại.

-Gremio


Không tệ cho một bài viết đầu tiên, anh bạn. +1.
ceejayoz

Có chút kiến ​​thức ngọt ngào đấy Gremio. Cảm ơn!! Tôi đã hoàn toàn loại bỏ vấn đề này và lưu trữ vấn đề trong nội bộ như một cái gì đó để xem xét vào một ngày sau đó, nhưng trở lại với nó giải pháp của bạn là một sự quyến rũ!
Hooligancat

3

Chúng tôi đã gặp vấn đề này và đã phát hiện ra rằng khi bảng tối ưu hóa được chạy trên một bảng trống, giá trị tăng tự động cũng được đặt lại. Xem báo cáo lỗi MySQL này .

Như một cách giải quyết, bạn có thể làm:

ALTER TABLE a AUTO_INCREMENT=3 ENGINE=innoDB;

Thay vì OPTIMIZE TABLE.

Có vẻ như đây là những gì MySQL thực hiện trong nội bộ (rõ ràng không đặt giá trị tăng tự động)


2

Chỉ cần một cú đánh trong bóng tối - nếu ứng dụng đang sử dụng TRUNCATE TABLEđể làm trống bảng khi xử lý xong, điều đó sẽ đặt lại trường tăng tự động. Đây là một cuộc thảo luận ngắn gọn về câu hỏi. Mặc dù liên kết đó đề cập rằng InnoDB không thiết lập lại auto_increments trên một trunc, nhưng nó đã được báo cáo là một lỗi và đã sửa một vài năm trước.

Giả sử tôi đoán là đúng, bạn có thể thay đổi từ cắt ngắn sang xóa để khắc phục vấn đề.


Tôi không nghĩ rằng chúng tôi đã sử dụng TRUNCATE, nhưng chúng tôi phải kiểm tra để đảm bảo. Thậm chí đã đi xa đến mức xác minh xuống cấp trình điều khiển PHP để đảm bảo. BUt chúng tôi không. Đánh giá cao các giải pháp có thể mặc dù.
Hooligancat

1

Chỉ có một thiết lập lại rõ ràng của giá trị đó, hoặc thả / tạo lại trường đó hoặc hoạt động bạo lực tương tự khác mới được đặt lại bộ đếm auto_increment. (TRUNCATE là một lý thuyết thực sự tốt.) Có vẻ như bạn không thể đột nhiên gói INT 32 bit khi giá trị cuối cùng bạn chứng kiến ​​chỉ là 600k. Nó chắc chắn không nên thiết lập lại chỉ vì bảng trống. Bạn có một lỗi mysql hoặc một cái gì đó trong mã PHP của bạn. Hoặc anh chàng trong tủ bên cạnh đang giở trò đồi bại với bạn.

Bạn có thể gỡ lỗi bằng cách bật nhật ký nhị phân , vì nó sẽ chứa các câu lệnh như thế này xuyên suốt:

SET INSERT_ID=3747670/*!*/;

Sau đó, ít nhất bạn có thể thấy mọi chi tiết về những gì đang xảy ra với bảng đó, bao gồm ngay trước khi bộ đếm đặt lại.


cảm ơn về mẹo gỡ lỗi. Đã được một thời gian kể từ khi tôi cần kiểm tra Serverfault và tôi đánh giá cao mẹo của bạn
Hooligancat

0

ALTER TABLE bảng_name Engine = MyISAM

Làm việc cho tôi. Bảng của chúng tôi luôn được giữ rất nhỏ, vì vậy không cần InnoDB.


Bạn có cần giao dịch?
Anthony Rutledge

0

InnoDB không lưu trữ giá trị gia tăng tự động trên đĩa do đó quên nó khi máy chủ MySQL bị tắt. Khi MySQL được khởi động lại, công cụ InnoDB sẽ khôi phục giá trị tăng tự động theo cách này : SELECT (MAX(id) + 1) AS auto_increment FROM table. Đây là một lỗi được sửa trong phiên bản MySQL 8.0.

Thay đổi công cụ bảng để giải quyết vấn đề:

ALTER TABLE table ENGINE = MyISAM

Hoặc cập nhật máy chủ MySQL lên phiên bản 8.0 khi nó được phát hành.

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.