Câu trả lời:
Đây là một "câu hỏi thi / phỏng vấn" rất phổ biến. Tôi sẽ trả lời tốt nhất có thể:
Trong các định dạng hàng tiêu chuẩn cho InnoDB và MyISAM (động / gọn) a VARCHAR(50)
và a VARCHAR(255)
sẽ lưu trữ văn bản chuỗi theo cùng một cách - 1 byte cho độ dài và chuỗi thực tế có từ 1 đến 4 byte cho mỗi ký tự (tùy thuộc vào mã hóa và các ký tự thực tế được lưu trữ).
Trong thực tế, nếu tôi nhớ chính xác, tôi nhớ lại ai đó đã sửa đổi từ điển dữ liệu bằng trình soạn thảo thập lục phân để thay đổi một cái gì đó giống như VARCHAR(50)
thành một VARCHAR(100)
, do đó nó có thể được thực hiện một cách linh hoạt (thông thường, đòi hỏi phải xây dựng lại bảng). Và điều đó là có thể, bởi vì dữ liệu thực tế không bị ảnh hưởng bởi sự thay đổi đó.
Điều đó không đúng với VARCHAR(256)
, bởi vì sau đó luôn cần 2 byte (ít nhất) cho độ dài.
Vì vậy, điều đó có nghĩa là chúng ta nên luôn luôn làm VARCHAR(255)
, phải không? Không. Có nhiều lý do.
Mặc dù InnoDB có thể lưu trữ một varchar theo cách năng động, nhưng điều đó không đúng với các công cụ khác. MyISAM có định dạng kích thước hàng cố định và các bảng NHỚ luôn được cố định về kích thước. Chúng ta có nên quan tâm đến những động cơ khác? Có, chúng ta nên, bởi vì ngay cả khi chúng ta không sử dụng chúng trực tiếp, các bảng NHỚ vẫn được sử dụng rất phổ biến cho các kết quả trung gian (các bảng tạm thời trên bộ nhớ) và vì các kết quả không được biết trước, bảng phải được tạo với kích thước tối đa có thể - VARCHAR(255)
nếu đó là loại của chúng tôi. Nếu bạn có thể nghĩ về không gian bị lãng phí, nếu chúng tôi đang sử dụng 'utf8' charset
mã hóa của MySQL , MEMORY sẽ dành 2 byte cho độ dài + 3 * 255 byte mỗi hàng(đối với các giá trị có thể chỉ mất một vài byte trên InnoDB). Đó là gần 1GB trên bảng 1 triệu - chỉ dành cho VARCHAR. Điều này không chỉ gây ra căng thẳng bộ nhớ không cần thiết, nó có thể kích động các hành động được thực hiện trên đĩa, có khả năng làm chậm nó hàng ngàn lần. Tất cả điều đó là do sự lựa chọn kém về kiểu dữ liệu được xác định của nó (độc lập với nội dung).
Nó cũng có một số hậu quả đối với InnoDB. Kích thước chỉ mục được giới hạn ở 3072 byte và các chỉ mục cột đơn, đến 767 byte *. Vì vậy, rất có khả năng bạn sẽ không thể lập chỉ mục đầy đủ mộtVARCHAR(255)
trường (giả sử bạn sử dụng utf8 hoặc bất kỳ mã hóa độ dài biến nào khác).
Ngoài ra, kích thước hàng nội tuyến tối đa cho InnoDB là một nửa trang (khoảng 8000 byte) và các trường có chiều dài thay đổi như BLOB hoặc varchar, có thể được lưu ngoài trang nếu chúng không vừa trên nửa trang . Điều đó có một số hậu quả trong hiệu suất (đôi khi tốt, đôi khi xấu, tùy thuộc vào cách sử dụng) không thể bỏ qua. Điều này gây ra một số điều kỳ lạ giữa các định dạng COMPACT và NĂNG ĐỘNG. Xem, ví dụ: lỗi 1118: kích thước hàng quá lớn. quán trọ utf8
Cuối cùng nhưng không kém phần quan trọng, như @ypercube đã nhắc nhở tôi, có thể cần nhiều hơn 1 byte cho độ dài ngay cả khi bạn đang sử dụng VARCHAR(255)
, vì định nghĩa là bằng ký tự, trong khi độ dài lưu trữ byte. Ví dụ: REPEAT('ñ', 255)
có hơn 2 ^ 255 byte trong utf8, do đó, nó sẽ cần nhiều hơn 1 byte để lưu trữ độ dài của nó:
mysql> SELECT LENGTH(REPEAT('ñ', 255));
+---------------------------+
| LENGTH(REPEAT('ñ', 255)) |
+---------------------------+
| 510 |
+---------------------------+
1 row in set (0.02 sec)
mysql> SELECT CHAR_LENGTH(REPEAT('ñ', 255));
+--------------------------------+
| CHAR_LENGTH(REPEAT('ñ', 255)) |
+--------------------------------+
| 255 |
+--------------------------------+
1 row in set (0.00 sec)
Vì vậy, lời khuyên chung là sử dụng loại nhỏ nhất có thể , bởi vì nó có khả năng có thể tạo ra các vấn đề về hiệu suất hoặc quản lý. A VARCHAR(100)
tốt hơn VARCHAR(255)
(mặc dù a VARCHAR(20)
sẽ tốt hơn), ngay cả khi bạn không biết độ dài chính xác. Cố gắng bảo thủ vì, trừ khi bảng quá lớn, bạn luôn có thể thay đổi định nghĩa sau.
Cập nhật: Vì sự phổ biến bùng nổ của các chuỗi có độ dài thay đổi, ví dụ, với việc sử dụng biểu tượng cảm xúc, Oracle đã thúc đẩy cải thiện hiệu suất cho những trường hợp đó. Trong các phiên bản MySQL mới nhất (5.6, 5.7), InnoDB đã được đặt làm công cụ mặc định cho cả bảng tạm thời nội tại và rõ ràng có nghĩa là các trường có độ dài thay đổi hiện là công dân hạng nhất. Điều đó có nghĩa là có thể có ít lý do hơn để có độ dài ký tự rất hạn chế (nhưng chúng vẫn tồn tại).
(*) Thứ hai Cập nhật : large_prefix_index đã được kích hoạt theo mặc định trên các phiên bản MySQL mới nhất (8.0), nhưng điều đó vẫn đúng đối với các phiên bản cũ hoặc nếu bạn đang sử dụng tập tin InnoDB lagacy / định dạng hàng (trừ động hoặc nén), nhưng bây giờ theo mặc định, các chỉ mục cột đơn có thể lên tới 3072 byte.
Quên về tiền tố 1- so với 2 byte trên VARCHARs
.
Câu hỏi về 255 đã được hỏi và trả lời nhiều lần.
VARCHARs
có thể dẫn đến thất bại CREATE TABLE
.MEMORY
bảng, với VARCHARs
biến thành VARCHAR
. Điều này có nghĩa là, ví dụ, VARCHAR(255) CHARACTER SET utf8mb4
muốn có độ dài cố định 1020 byte. (Điều này sẽ thất bại và nó sẽ thoái hóa khi sử dụng MyISAM.)Điểm mấu chốt: Đừng mù quáng sử dụng 255 (hoặc 256); làm những gì có ý nghĩa cho lược đồ.