Có bất lợi nào khi sử dụng varchar chung (255) cho tất cả các trường dựa trên văn bản không?


100

Tôi có một contactsbảng chứa các lĩnh vực như postcode, first name, last name, town, country, phone numbervv, tất cả đều được định nghĩa là VARCHAR(255)mặc dù không ai trong số các lĩnh vực này bao giờ sẽ đến gần có 255 ký tự. (Nếu bạn đang thắc mắc, đó là cách này vì Ruby on Rails chuyển đổi ánh xạ các trường Chuỗi thành VARCHAR(255)theo mặc định và tôi không bao giờ bận tâm đến việc ghi đè nó).

Kể từ VARCHAR sẽ chỉ lưu trữ các số ký tự thực tế của lĩnh vực này (cùng với chiều dài trường), là có bất kỳ lợi thế riêng biệt (hiệu suất hay cách khác) để sử dụng, chẳng hạn, VARCHAR(16)qua VARCHAR(255)?

Ngoài ra, hầu hết các trường này đều có chỉ mục trên đó. Kích thước VARCHAR lớn hơn trên trường có ảnh hưởng đến kích thước hoặc hiệu suất của chỉ mục không?

FYI Tôi đang sử dụng MySQL 5.


2
@ceejayoz, nói rằng câu trả lời được chấp nhận là không chính xác mà không giải thích lý do tại sao không thực sự hữu ích. Điều khiến nó thậm chí còn tồi tệ hơn là câu trả lời được chấp nhận có thể thay đổi theo thời gian và nhận xét của bạn sẽ khiến mọi người nhầm lẫn rằng câu trả lời được chấp nhận mới là không chính xác.
Gili

1
@Gili đã xóa nhận xét của tôi vì OP dường như đã thay đổi sự chấp nhận của họ. Điểm tốt, trong tương lai tôi sẽ chỉ ra câu trả lời mà tôi đang nói đến và tại sao.
ceejayoz

Một số câu trả lời khác tại câu hỏi trùng lặp này, stackoverflow.com/questions/1262174/...
James McMahon

Câu trả lời:


129

Trong bộ nhớ, VARCHAR(255)đủ thông minh để chỉ lưu trữ độ dài bạn cần trên một hàng nhất định, không giống như hàng CHAR(255)sẽ luôn lưu trữ 255 ký tự.

Nhưng vì bạn đã gắn thẻ câu hỏi này với MySQL, tôi sẽ đề cập đến một mẹo dành riêng cho MySQL: khi các hàng được sao chép từ lớp công cụ lưu trữ sang lớp SQL, VARCHARcác trường được chuyển đổi CHARđể đạt được lợi thế khi làm việc với các hàng có chiều rộng cố định. Vì vậy, các chuỗi trong bộ nhớ trở nên được đệm bằng chiều dài tối đa của VARCHARcột đã khai báo của bạn .

Khi truy vấn của bạn hoàn toàn tạo ra một bảng tạm thời, chẳng hạn như trong khi sắp xếp hoặc GROUP BY, điều này có thể sử dụng nhiều bộ nhớ. Nếu bạn sử dụng nhiều VARCHAR(255)trường cho dữ liệu không cần quá dài, điều này có thể làm cho bảng tạm thời rất lớn.

Bạn cũng có thể muốn biết rằng hành vi "đệm ra" này có nghĩa là một chuỗi được khai báo với bộ ký tự utf8 đệm ra ba byte cho mỗi ký tự ngay cả đối với chuỗi bạn lưu trữ với nội dung một byte (ví dụ: ký tự ascii hoặc latin1). Và tương tự như vậy, bộ ký tự utf8mb4 làm cho chuỗi thêm vào bốn byte cho mỗi ký tự trong bộ nhớ.

Vì vậy, một VARCHAR(255)trong utf8 lưu trữ một chuỗi ngắn như "Không có ý kiến" chiếm 11 byte trên đĩa (mười ký tự ký tự thấp hơn, cộng thêm một byte cho độ dài) nhưng nó chiếm 765 byte trong bộ nhớ và do đó trong bảng tạm thời hoặc kết quả được sắp xếp.

Tôi đã giúp những người dùng MySQL vô tình tạo bảng tạm thời 1,5GB thường xuyên và làm đầy không gian đĩa của họ. Họ có rất nhiều VARCHAR(255)cột trong thực tế lưu trữ các chuỗi rất ngắn.

Tốt nhất nên xác định cột dựa trên loại dữ liệu mà bạn định lưu trữ. Nó có lợi ích để thực thi các ràng buộc liên quan đến ứng dụng, như những người khác đã đề cập. Nhưng nó có những lợi ích vật lý để tránh lãng phí bộ nhớ mà tôi đã mô tả ở trên.

Tất nhiên, thật khó để biết địa chỉ bưu điện dài nhất là gì, đó là lý do tại sao nhiều người chọn một VARCHARđịa chỉ dài chắc chắn dài hơn bất kỳ địa chỉ nào. Và 255 là thông lệ vì nó là độ dài tối đa của a VARCHARmà độ dài có thể được mã hóa bằng một byte. Nó cũng là VARCHARđộ dài tối đa trong MySQL cũ hơn 5.0.


6
Tôi luôn luôn nghĩ rằng 255đã được sử dụng do đó độ dài của chuỗi có thể phù hợp với một byte đơn
BlueRaja - Danny Pflughoeft

3
@BlueRaja: Điều đó có thể đúng với cơ sở dữ liệu có cấu trúc tệp nội bộ mã hóa độ dài của một chuỗi trong một byte đơn hoặc nếu chúng mã hóa các chuỗi ngắn trong một byte đơn. Nhưng nó không còn đúng với hầu hết các cơ sở dữ liệu.
Bill Karwin

7
@BlueRaja: InnoDB không lưu trữ độ dài của varchar sau, nó lưu trữ một loạt các hiệu số trường cho tất cả các trường trong hàng. Các hiệu số trường này có thể là 1 byte nếu tổng kích thước hàng nhỏ hơn 127 byte, hoặc 2 byte khác. Xem forge.mysql.com/wiki/MySQL_Internals_InnoDB
Bill Karwin

6
@BlueRaja: MyISAM (dành cho những người vẫn sử dụng nó) lưu trữ độ dài varchar và chúng có thể được lưu trữ trong 1 hoặc 2 byte. Tuy nhiên: "Khi gửi một khóa tới trình xử lý cho index_read () hoặc records_in_range, chúng tôi luôn sử dụng độ dài 2 byte cho VARCHAR để làm cho mọi thứ đơn giản hơn." Xem forge.mysql.com/wiki/MySQL_Internals_MyISAM
Bill Karwin

1
một câu hỏi - sắp xếp và nhóm theo bất kỳ trường nào hoặc chính trường varchar?
Rohit Banga

24

Ngoài các cân nhắc về kích thước và hiệu suất khi đặt kích thước của varchar (và có thể quan trọng hơn, vì việc lưu trữ và xử lý sẽ rẻ hơn mỗi giây), nhược điểm của việc sử dụng varchar (255) "chỉ vì" là làm giảm tính toàn vẹn của dữ liệu .

Việc xác định giới hạn tối đa cho các chuỗi là điều nên làm để ngăn các chuỗi dài hơn dự kiến ​​vào RDBMS và gây ra ghi đè bộ đệm hoặc ngoại lệ / lỗi sau này khi truy xuất và phân tích cú pháp các giá trị từ cơ sở dữ liệu dài hơn (nhiều byte) hơn mong đợi.

Ví dụ: nếu bạn có một trường chấp nhận các chuỗi hai ký tự cho chữ viết tắt của quốc gia thì bạn không có lý do gì có thể tưởng tượng được để mong đợi người dùng của mình (trong ngữ cảnh này là các lập trình viên) nhập tên quốc gia đầy đủ. Vì bạn không muốn họ nhập "Antigua và Barbuda" (AG) hoặc "Đảo Heard và Quần đảo McDonald" (HM), bạn không cho phép nó ở lớp cơ sở dữ liệu. Ngoài ra, có khả năng một số lập trình viên chưa RTFMed tài liệu thiết kế ( chắc chắn tồn tại ) để biết không làm điều này.

Đặt trường để chấp nhận hai ký tự và để RDBMS xử lý nó (một cách dễ dàng bằng cách cắt bớt hoặc không khéo léo bằng cách từ chối SQL của chúng với một lỗi).

Ví dụ về dữ liệu thực không có lý do vượt quá độ dài nhất định:

  • Mã Bưu chính Canada có định dạng A1A1A1 và luôn có độ dài 6 ký tự, ngay cả đối với Ông già Noel (6 ký tự không bao gồm khoảng trắng có thể được chỉ định để dễ đọc).
  • địa chỉ email - tối đa 64 byte trước @, tối đa 255 byte sau. Đừng bao giờ nữa, kẻo bạn phá vỡ Internet.
  • Số điện thoại Bắc Mỹ không bao giờ nhiều hơn 10 chữ số (không bao gồm mã quốc gia).
  • Máy tính đang chạy (phiên bản gần đây của) Windows không được có tên máy tính dài hơn 63 byte , mặc dù không khuyến khích sử dụng nhiều hơn 15 và sẽ phá vỡ trang máy chủ Windows NT của bạn.
  • Các chữ viết tắt của tiểu bang là 2 ký tự (như mã quốc gia được lấy mẫu ở trên)
  • Các số theo dõi của UPS có độ dài 18-, 12-, 11- hoặc 9 ký tự. Các số 18 ký tự bắt đầu bằng "1Z" và 11 ký tự bắt đầu bằng "T" khiến bạn tự hỏi làm thế nào họ phân phối tất cả các gói hàng đó nếu họ không biết sự khác biệt giữa chữ và số.

Và như thế...

Dành thời gian để suy nghĩ về dữ liệu của bạn và các giới hạn của nó. Nếu bạn là một kiến ​​trúc sư, nhà phát triển hoặc lập trình viên, thì đó là công việc của bạn .

Bằng cách sử dụng varchar (n) thay vì varchar (255), bạn loại bỏ được vấn đề khi người dùng (người dùng cuối, lập trình viên, các chương trình khác) nhập dữ liệu dài bất ngờ sẽ quay lại ám ảnh mã của bạn sau này.

Và tôi không nói rằng bạn cũng không nên triển khai hạn chế này trong mã logic nghiệp vụ được ứng dụng của bạn sử dụng.


5
Mã bưu chính của Canada thực sự có 7 chữ số, khoảng trống ở giữa là quan trọng và phải được hiển thị trên nhãn gửi thư. Các số điện thoại Bắc Mỹ có thể có nhiều hơn 10 chữ số nếu có sự mở rộng. Nếu bạn không thể lưu trữ các phần mở rộng số điện thoại, thì 10 chữ số cũng không sao, nhưng bạn có thể sẽ hối tiếc.
Kibbee 30/09/09

3
Chắc chắn có một trường hợp hạn chế tính toàn vẹn của dữ liệu. Mặc dù vậy, vẫn dễ bị hạn chế. Áp đặt các hạn chế cho dữ liệu bạn kiểm soát và áp đặt các hạn chế lành mạnh cho các yêu cầu dữ liệu mà bạn không thể kiểm soát. Các hạn chế về số điện thoại và e-mail của bạn là lành mạnh (giả sử bạn không bao giờ quốc tế hóa). Yêu cầu của bạn nói rằng việc cắt ngắn mã quốc gia gồm hai ký tự là một điều "duyên dáng" là điên rồ. Bạn biết đã có lỗi, đừng cắt ngắn và chấp nhận. Nếu bạn cắt ngắn thì khả năng cao là bạn sẽ nhận được mã quốc gia không chính xác.
coderjoe 23/10/09

Hầu hết các ứng dụng sẽ phải xác nhận dữ liệu được thực hiện trước khi gửi nó vào cơ sở dữ liệu ...
Cobby

2
Chắc chắn rồi. Phần lớn. Nhưng tôi cảm thấy rằng ở đây bạn đang giả định rằng một nhà phát triển đang phát triển một ứng dụng mới cho cơ sở dữ liệu hiện có nhận thức được các hạn chế đối với dữ liệu (chúng tôi không phải tất cả các chuyên gia về mọi loại dữ liệu và cách nó được triển khai trong mọi cơ sở dữ liệu ). Chỉ vì bạn có thể xác thực dữ liệu trong ứng dụng của mình không có nghĩa là bạn đã làm như vậy.
shufler

3
the design documentation (which surely exists)Hả. : D
Camilo Martin

14

Tôi với bạn. Sự chú ý cầu kỳ đến chi tiết là một cơn đau ở cổ và có giá trị hạn chế.

Ngày xửa ngày xưa, đĩa là một mặt hàng quý giá và chúng ta đã phải tốn nhiều công sức để tối ưu hóa nó. Giá lưu trữ đã giảm 1.000, khiến thời gian dành cho việc vắt từng byte ít giá trị hơn.

Nếu bạn chỉ sử dụng các trường CHAR, bạn có thể nhận được các hàng có độ dài cố định. Điều này có thể tiết kiệm một số đĩa được khôi phục lại thực nếu bạn đã chọn kích thước chính xác cho các trường. Bạn có thể nhận được dữ liệu dày đặc hơn (ít I / O hơn để quét bảng) và cập nhật nhanh hơn (dễ dàng xác định các không gian mở trong một khối để cập nhật và chèn).

Tuy nhiên, nếu bạn ước tính quá mức kích thước của mình hoặc kích thước dữ liệu thực tế của bạn có thể thay đổi, bạn sẽ lãng phí dung lượng với các trường CHAR. Dữ liệu sẽ ít được đóng gói dày đặc hơn (dẫn đến nhiều I / O hơn để truy xuất lớn).

Nói chung, lợi ích về hiệu suất từ ​​việc cố gắng đặt một kích thước vào các trường thay đổi là rất nhỏ. Bạn có thể dễ dàng chuẩn bằng cách sử dụng VARCHAR (255) so với CHAR (x) để xem liệu bạn có thể đo lường sự khác biệt hay không.

Tuy nhiên, đôi khi, tôi cần cung cấp gợi ý "nhỏ", "trung bình", "lớn". Vì vậy, tôi sử dụng 16, 64 và 255 cho các kích thước.


13

Ngày nay, tôi không thể tưởng tượng nó thực sự quan trọng hơn thế nữa.

Việc sử dụng các trường có độ dài thay đổi sẽ phải tốn một khoản chi phí tính toán, nhưng với sự dư thừa của CPU ngày nay, điều đó thậm chí không đáng xem xét. Hệ thống I / O chậm đến mức không tồn tại bất kỳ chi phí tính toán nào để xử lý các varchars một cách hiệu quả. Trên thực tế, giá của một varchar tính toán có lẽ là một phần thắng ròng đối với lượng không gian đĩa được tiết kiệm bằng cách sử dụng các trường độ dài thay đổi trên các trường độ dài cố định. Bạn rất có thể có mật độ hàng lớn hơn.

Bây giờ, sự phức tạp của các trường varchar là bạn không thể dễ dàng định vị một bản ghi thông qua số bản ghi của nó. Khi bạn có kích thước hàng có độ dài cố định (với các trường độ dài cố định), việc tính toán khối đĩa mà id hàng trỏ đến là một điều dễ hiểu. Với kích thước hàng có độ dài thay đổi, loại đó sẽ xuất hiện trong cửa sổ.

Vì vậy, bây giờ bạn cần duy trì một số loại chỉ mục số bản ghi, giống như bất kỳ khóa chính nào khác, HOẶC bạn cần tạo một mã định danh hàng mạnh mẽ mã hóa các chi tiết (chẳng hạn như khối, v.v.) vào mã định danh. Tuy nhiên, nếu bạn làm điều đó, id sẽ phải được tính toán lại nếu hàng được di chuyển trên bộ nhớ liên tục. Không có vấn đề gì lớn, chỉ cần viết lại tất cả các mục chỉ mục và đảm bảo rằng bạn a) không bao giờ để lộ nó cho người tiêu dùng hoặc b) không bao giờ khẳng định rằng con số đó là đáng tin cậy.

Nhưng vì chúng ta có các trường varchar ngày nay, giá trị duy nhất của varchar (16) trên varchar (255) là DB sẽ thực thi giới hạn 16 ký tự trên varchar (16). Nếu mô hình DB được cho là thực sự đại diện cho mô hình dữ liệu vật lý, thì việc có độ dài các trường có thể có giá trị. Tuy nhiên, nếu nó chỉ đơn giản là "lưu trữ" chứ không phải là "mô hình VÀ lưu trữ", thì không cần gì cả.

Sau đó, bạn chỉ cần phân biệt giữa trường văn bản có thể lập chỉ mục (như varchar) và trường nào đó không (như trường văn bản hoặc CLOB). Các trường có thể lập chỉ mục có xu hướng có giới hạn về kích thước để tạo điều kiện cho chỉ mục trong khi các trường CLOB thì không (trong lý do).


5

Theo kinh nghiệm của tôi, nếu bạn cho phép một kiểu dữ liệu gồm 255 ký tự, một số người dùng ngu ngốc (hoặc một số người thử nghiệm có kinh nghiệm) sẽ thực sự điền vào đó.

Sau đó, bạn gặp tất cả các loại vấn đề, bao gồm cả dung lượng bạn cho phép cho các trường đó trong báo cáo và hiển thị trên màn hình trong ứng dụng của bạn. Chưa kể đến khả năng vượt quá giới hạn mỗi hàng cho dữ liệu trong cơ sở dữ liệu của bạn (nếu bạn có nhiều hơn một vài trong số 255 trường ký tự này).

Dễ dàng hơn nhiều để chọn một giới hạn hợp lý ngay từ đầu, sau đó thực thi điều đó thông qua ứng dụng và cơ sở dữ liệu.


0

Thực hành tốt là chỉ phân bổ một chút so với những gì bạn cần. Số điện thoại sẽ không bao giờ lớn như vậy.

Một lý do là trừ khi bạn xác nhận các mục nhập lớn, chắc chắn ai đó sẽ sử dụng tất cả những gì có. Sau đó, bạn có thể hết dung lượng trong hàng của mình. Tôi không chắc về giới hạn MySQL nhưng 8060 là kích thước hàng tối đa trong MS SQL.

Giá trị mặc định bình thường hơn sẽ là 50 imho, và sau đó tăng lên nếu cần chứng minh điều đó.


Cảm ơn. Tôi chắc chắn đồng ý về việc nó là một thực hành tốt. Đó là khía cạnh hiệu suất mà tôi thực sự muốn làm rõ
Olly

0

Trong ngữ cảnh mysql, nó có thể trở nên quan trọng khi làm việc với các chỉ mục trên các cột varchar đã nói, vì mysql có giá trị tối đa. giới hạn 767byte cho mỗi hàng chỉ mục.

Điều này có nghĩa là khi thêm một chỉ mục trên một số cột varchar 255, bạn có thể đạt đến giới hạn này khá nhanh / thậm chí nhanh hơn trên các cột utf8 hoặc utf8mb4 như đã chỉ ra trong các câu trả lời ở trên

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.