2010-04-10 11 views
49

Tôi đang triển khai một ứng dụng cơ sở dữ liệu và tôi sẽ sử dụng cả JavaDB lẫn MySQL làm cơ sở dữ liệu. Tôi có một cột ID trong bảng của tôi có số nguyên như là loại và tôi sử dụng cơ sở dữ liệu auto_increment-chức năng cho giá trị.Điều gì sẽ xảy ra khi auto_increment trên cột nguyên đạt đến max_value trong cơ sở dữ liệu?

Nhưng điều gì sẽ xảy ra khi tôi nhận được hơn 2 (hoặc 4) tỷ bài viết và số nguyên là không đủ? Là số nguyên tràn và tiếp tục hoặc là một ngoại lệ ném mà tôi có thể xử lý?

Có, tôi có thể thay đổi miễn là kiểu dữ liệu, nhưng làm cách nào để kiểm tra khi nào cần thiết? Và tôi nghĩ rằng có vấn đề với việc nhận các hàm last_inserted_id() nếu tôi sử dụng lâu dài như kiểu dữ liệu cho cột ID.

Trả lời

42

Jim Martin bình luận từ §3.6.9. "Using AUTO_INCREMENT" các tài liệu MySQL:

Chỉ trong trường hợp có bất kỳ câu hỏi, lĩnh vực AUTO_INCREMENT/KHÔNG quấn /. Khi bạn đạt đến giới hạn cho kích thước trường, INSERT sẽ tạo ra lỗi. (Theo Jeremy Cole)

Một test nhanh với MySQL 5.1.45 kết quả trong một lỗi của:

ERROR 1467 (HY000): Không thể đọc giá trị auto-increment từ công cụ lưu trữ

Bạn có thể kiểm tra lỗi đó khi chèn và thực hiện hành động thích hợp.

8

Bạn sẽ biết khi nào nó sẽ tràn khi nhìn vào ID lớn nhất. Bạn nên thay đổi nó trước khi bất kỳ ngoại lệ thậm chí đến gần được ném.

Thực tế, bạn nên thiết kế với kiểu dữ liệu đủ lớn để bắt đầu. Hiệu năng cơ sở dữ liệu của bạn sẽ không bị ảnh hưởng ngay cả khi bạn sử dụng ID 64 bit ngay từ đầu.

38

Chỉ cần bình tĩnh các dây thần kinh, xem xét việc này:

Giả sử bạn có một cơ sở dữ liệu mà chèn một giá trị mới cho mỗi khi người dùng thực hiện một số loại giao dịch trên trang web của bạn.

Với số nguyên 64 bit làm ID thì đây là điều kiện tràn: Với dân số thế giới 6 tỷ thì nếu mọi người trên trái đất thực hiện giao dịch một lần mỗi giây mỗi ngày và mỗi năm (không nghỉ) sẽ mất hơn 80 năm để id của bạn quấn quanh.

Tức là, chỉ google cần xem xét một cách mơ hồ vấn đề này đôi khi trong giờ nghỉ giải lao.

+2

Rất tiếc, chỉ cần sửa lỗi sẽ mất hơn 9 năm :) Sau 1 phút, 360 tỷ tnx sẽ xảy ra. Sau 1h, hóa đơn 21600. Trong 1 ngày, 518400 tỷ tnx sẽ được xác minh. 1 năm: 1892160 nghìn tỷ. Sau 8 năm, 15.137.280 ngàn tỷ sẽ được lưu trong db. Giới hạn của UNSIGNED BIGINT là 18.446.744 nghìn tỷ. –

+1

bạn nhận được một số không thêm trong 1 năm. vì vậy nó sẽ là khoảng 97 năm. – lockedscope

+0

Và nếu tôi có 2000 proxy thực hiện một cuộc tấn công chèn tung ra nhiều chủ đề/yêu cầu? . Hoặc ví dụ tôi có một chức năng tải lên lịch sử với (60.000 mục) để tải lên lịch sử đó sẽ yêu cầu ít yêu cầu hơn. –

-1

Đối với MySQL 5.6, 3.6.9 Using AUTO_INCREMENT trong nói:

Sử dụng các kiểu dữ liệu số nguyên nhỏ nhất cho cột AUTO_INCREMENT đó là đủ lớn để giữ giá trị chuỗi tối đa mà bạn sẽ cần. Khi cột đạt đến giới hạn trên của kiểu dữ liệu, nỗ lực tiếp theo để tạo một số thứ tự không thành công.

0

Tôi muốn chia sẻ trải nghiệm cá nhân mà tôi vừa có về điều này. Sử dụng Nagios + Check_MK + NDOUtils. NDOUtils lưu trữ tất cả các kiểm tra trong một bảng gọi là nagios_servicechecks. Khóa chính là một ký tự auto_increment int đã được ký. Điều gì sẽ xảy ra với MySQL khi giới hạn này được thay đổi?Vâng, trong trường hợp của tôi, MySQL xóa tất cả các hồ sơ nhưng cuối cùng. Bảng bây giờ hầu như trống. Mỗi lần một bản ghi mới được chèn vào bản ghi cũ sẽ bị xóa. Đừng lý do tại sao điều này xảy ra, nhưng thực tế là tôi đã mất tất cả hồ sơ của mình. IDOUtils, được sử dụng với Icinga (không phải Nagios), cố định vấn đề này thay đổi int bởi một bigint. Nó không tạo ra lỗi.

2

Câu trả lời ở đây nêu rõ điều gì xảy ra, nhưng chỉ có một câu trả lời cho biết cách phát hiện sự cố (và sau đó chỉ sau khi lỗi xảy ra). Nói chung, nó là hữu ích để có thể phát hiện những điều này trước khi họ trở thành một vấn đề sản xuất, vì vậy tôi đã viết một truy vấn để phát hiện khi một tràn sắp xảy ra:

SELECT 
    c.TABLE_CATALOG, 
    c.TABLE_SCHEMA, 
    c.TABLE_NAME, 
    c.COLUMN_NAME 
FROM information_schema.COLUMNS AS c 
JOIN information_schema.TABLES AS t USING (TABLE_CATALOG, TABLE_SCHEMA, TABLE_NAME) 
WHERE c.EXTRA LIKE '%auto_increment%' 
    AND t.AUTO_INCREMENT/CASE c.DATA_TYPE 
     WHEN 'TINYINT' THEN IF(c.COLUMN_TYPE LIKE '% UNSIGNED', 255, 127) 
     WHEN 'SMALLINT' THEN IF(c.COLUMN_TYPE LIKE '% UNSIGNED', 65535, 32767) 
     WHEN 'MEDIUMINT' THEN IF(c.COLUMN_TYPE LIKE '% UNSIGNED', 16777215, 8388607) 
     WHEN 'INT' THEN IF(c.COLUMN_TYPE LIKE '% UNSIGNED', 4294967295, 2147483647) 
     WHEN 'BIGINT' THEN IF(c.COLUMN_TYPE LIKE '% UNSIGNED', '18446744073709551615', 9223372036854775807) # need to quote because column type defaults to unsigned. 
     ELSE 0 
    END > .9; # 10% buffer 

Hy vọng điều này sẽ giúp người ở đâu đó.