MySQL: VARCHAR lớn so với văn bản?


845

Tôi đã có một bảng thông báo trong MySQL ghi lại các tin nhắn giữa những người dùng. Ngoài các id và loại thông báo điển hình (tất cả các loại số nguyên) tôi cần lưu văn bản thông báo thực tế dưới dạng VARCHAR hoặc TEXT. Tôi đang đặt giới hạn đầu cuối là 3000 ký tự, điều đó có nghĩa là các tin nhắn sẽ không bao giờ được chèn vào db lâu hơn thế này.

Có một lý do để đi với VARCHAR (3000) hoặc văn bản không? Có điều gì đó về việc chỉ viết VARCHAR (3000) mà cảm thấy hơi phản cảm. Tôi đã xem qua các bài đăng tương tự khác trên Stack Overflow nhưng sẽ rất tốt để có được lượt xem cụ thể cho loại lưu trữ thư phổ biến này.


27
Một chút cũ, nhưng tôi đến đây vì tôi gặp phải một vấn đề khiến tôi suy nghĩ về điều này. Trong trường hợp của tôi, hình thức mặt trước của tôi bị giới hạn ở 2.000 ký tự nhưng mã hóa ẩn trong phương thức lưu trữ của tôi được mã hóa các ký tự quốc tế thành nhiều ký tự (có thể rõ ràng ở bất kỳ đâu từ 3 - 12 mỗi ký tự). Vì vậy, 2.000 của tôi đột nhiên trở thành lên đến 24.000. Có gì đó để suy nghĩ về ...
James S

3
Tôi đã tìm thấy văn bản nhanh hơn đáng kể cho nhiều lần chèn đồng thời.
Ray S.

1
@JamesS: utf8mb4 ...>. <
không thể chia sẻ

10
@RickJames xem xét việc đăng câu trả lời cập nhật, thay vì đóng câu hỏi
Yvette

3
@YvetteColomb - Tôi đã thêm Câu trả lời. Tôi chủ yếu muốn thoát khỏi Câu trả lời được chấp nhận vì nó đã lỗi thời . Tôi đã đến hỏi đáp vì có ai đó trích dẫn thông tin không chính xác, nói rằng "754 lượt upvote, vì vậy nó phải đúng". OK, tôi cũng chỉnh sửa câu trả lời đã được phê duyệt. (Mặc dù điều đó cảm thấy không phù hợp.)
Rick James

Câu trả lời:


811
  • TEXTBLOB có thể bằng cách lưu trữ ngoài bảng với bảng chỉ cần có một con trỏ đến vị trí lưu trữ thực tế. Nơi nó được lưu trữ phụ thuộc vào rất nhiều thứ như kích thước dữ liệu, kích thước cột, row_format và phiên bản MySQL.

  • VARCHARđược lưu trữ nội tuyến với bảng. VARCHARnhanh hơn khi kích thước hợp lý, sự đánh đổi sẽ nhanh hơn phụ thuộc vào dữ liệu và phần cứng của bạn, bạn muốn đánh giá kịch bản trong thế giới thực với dữ liệu của mình.


148
+1: VARCHAR (lưu trữ nội tuyến) thường nhanh hơn NẾU dữ liệu thường được truy xuất (được bao gồm bởi hầu hết các truy vấn). Tuy nhiên, đối với một khối lượng lớn dữ liệu thường không được truy xuất (nghĩa là không được tham chiếu bởi bất kỳ truy vấn nào), thì tốt hơn là không có dữ liệu được lưu trữ nội tuyến. Có giới hạn trên về kích thước hàng, đối với dữ liệu được lưu trữ nội tuyến.
spencer7593

21
@Pacerier: lợi ích chính xác của việc tránh lưu trữ "nội tuyến" là tăng số lượng hàng có thể được lưu trữ trong một khối, có nghĩa là các hàng trong bảng chiếm ít khối hơn trong bộ đệm của bộ đệm InnoDB (dấu chân bộ nhớ nhỏ hơn) và có nghĩa là ít hơn các khối được chuyển đến và từ đĩa (giảm I / O). Nhưng, đây chỉ là một lợi ích về hiệu suất nếu các cột được lưu trữ "hàng ngoài" phần lớn không được kiểm soát bởi các truy vấn. Nếu các cột "ngoài hàng" được tham chiếu bởi hầu hết các truy vấn, thì lợi ích đó phần lớn sẽ bay hơi. Nội tuyến được ưu tiên nếu các cột phù hợp với kích thước hàng tối đa và thường được tham chiếu.
spencer7593

231
"VARCHAR nhanh hơn khi kích thước hợp lý". Số ký tự "hợp lý" là bao nhiêu, 100? 1000? 100.000?
tim peterson

125
Câu trả lời này không đúng với InnoDB. Cả VARCHAR và BLOB / TEXT đều được lưu trữ nội tuyến với các cột khác nếu giá trị trên một hàng nhất định phù hợp với kích thước trang (16KB và mỗi trang phải giữ ít nhất hai hàng). Nếu chuỗi quá lớn cho điều đó, nó sẽ tràn sang các trang bổ sung. Xem mysqlperformanceblog.com/2010/02/09/blob-st Storage-in-innodb để được giải thích chi tiết.
Bill Karwin

14
@BillKarwin ... Nếu tôi hiểu chính xác thì sẽ không có sự khác biệt về hiệu năng giữa varcharblob/ texttrên InnoDB cho các mục văn bản nhỏ? Vì vậy, nó sau đó sẽ là khôn ngoan để chỉ làm mỗi varcharmột textloại và để cho các DB quản lý inline vs tràn?
ryvantage

473

Bạn có thể dự đoán bao lâu đầu vào của người dùng?

VARCHAR (X)

Trường hợp: tên người dùng, email, quốc gia, chủ đề, mật khẩu


BẢN VĂN

Trường hợp: tin nhắn, email, bình luận, văn bản được định dạng, html, mã, hình ảnh, liên kết


TRUNG TÂM

Trường hợp: cơ thể json lớn, sách ngắn đến trung bình, chuỗi csv


VĂN BẢN DÀI

Trường hợp: sách giáo khoa, chương trình, năm tập tin nhật ký, harry potter và chiếc cốc lửa, đăng nhập nghiên cứu khoa học


7
Dự đoán thực sự là một mục phụ ở đây. Đó thực sự là chiều dài dự kiến ​​tối đa nên là yếu tố quyết định. Các mục bạn đề cập nhiều hơn có thể dự đoán được chỉ theo cách đó vì chúng ngắn hơn các mục khác.
Andrew Barber

29
@ andrew-barber Đó là quan điểm của tôi. Tất cả các bài viết khác giải thích tốt về sự khác biệt nhưng không phải về các tình huống khi bạn thực sự phải đưa ra lựa chọn giữa hai. Tôi đã cố gắng chỉ ra việc sử dụng varchar để dự đoán ngắn là một lựa chọn tốt và sử dụng văn bản cho thời gian dài tùy ý là một lựa chọn tốt.
Michael J. Calkins

1
Nếu tất cả các cột đều ngắn và có thể dự đoán được (ví dụ: địa chỉ MAC, IMEI, v.v ... là những thứ không bao giờ thay đổi) thì hãy sử dụng các cột CHAR và bạn có thể cố định kích thước hàng của mình, điều này sẽ tăng tốc đáng kể nếu sử dụng MyISAM, có thể còn InnoDb mặc dù tôi không chắc về nó.
Matt

1
@ MichaelJ.Calkins Điều đó đã xảy ra trong MySQL 5.6. Bây giờ bạn cũng có tìm kiếm toàn văn bản trong InnoDB. Xem dev.mysql.com/doc/refman/5.6/en/fulltext-search.html
PhoneixS

7
Giới hạn ký tự: TINYTEXT: 255; VĂN BẢN: 65,535; TRUNG TÂM: 16.777.215; LONGTEXT: 4.294.967,29.
Victor Stoddard

218

Chỉ cần làm rõ thực tiễn tốt nhất:

  1. Các tin nhắn định dạng văn bản hầu như luôn được lưu trữ dưới dạng văn bản (chúng cuối cùng dài tùy ý)

  2. Các thuộc tính chuỗi nên được lưu trữ dưới dạng VARCHAR (tên người dùng đích, chủ đề, v.v ...).

Tôi hiểu rằng bạn đã có giới hạn kết thúc trước, điều này thật tuyệt vời cho đến khi không. * cười * Bí quyết là nghĩ DB tách biệt với các ứng dụng kết nối với nó. Chỉ vì một ứng dụng đặt giới hạn cho dữ liệu, không có nghĩa là dữ liệu bị giới hạn về bản chất.

Điều gì về bản thân các thông điệp buộc chúng không bao giờ được nhiều hơn 3000 ký tự? Nếu đó chỉ là một ràng buộc ứng dụng tùy ý (giả sử đối với hộp văn bản hoặc thứ gì đó), hãy sử dụng một TEXTtrường ở lớp dữ liệu.


"Cái nào tuyệt vời cho đến khi nó không" nghĩa là gì? "Không" đề cập đến điều gì?
Pacerier 16/07/2015

7
@Pacerier Để cho bạn một ví dụ về "không" James có khả năng về: Lấy ví dụ Twitter, người cho đến gần đây đã có giới hạn 140 ký tự cho các PM. Họ quyết định nó không còn hợp lý nữa và chọn loại bỏ hoàn toàn giới hạn đó. Nếu họ không nghĩ trước về điều đó (điều mà tôi khá chắc là có lẽ họ đã làm ...) thì họ đã chạy đến kịch bản được nêu ở trên.
PaulSkinner

9
Tôi vừa mới đưa lên cơ sở dữ liệu mới của chúng tôi và tôi cho rằng không ai có thể đặt hơn 2000 ký tự vào các hộp bình luận nhỏ của chúng tôi, và sau đó, như James lưu ý, tối nay nó đột nhiên "không ổn" vì một người dùng đã bỏ qua bình luận rất hợp lệ dài 2600 ký tự. Tôi đã sử dụng varchar (2000) nghĩ rằng nó không thể lâu hơn thế và tôi đã sai. Vì vậy, có, nó tuyệt vời cho đến khi nó không. Trong trường hợp của chúng tôi mà chỉ mất một vài ngày để hiển thị. Quy tắc dưới đây, Michael J. Calkins, tôi nghĩ rằng tôi sẽ sử dụng từ bây giờ. Văn bản cho tin nhắn, bình luận.
Lizardx

1
@Pacerier "thật tuyệt vời cho đến khi nó không tuyệt vời". Nói cách khác, nó hoạt động gần như mọi lúc và thật tuyệt vời ... ngoại trừ những tình huống đặc biệt khi nó không quá tuyệt vời.
Chuộc tội giới hạn

@Pacerier một ví dụ thú vị khác được đề cập trong các bình luận của câu trả lời được chọn, về cơ bản anh ta có giới hạn 2.000 ký tự phía trước nhưng các ký tự được giới thiệu nằm trong một bảng mã rằng trong thực tế sử dụng nhiều byte hơn các chữ cái bình thường, cơ sở dữ liệu của anh ta cần không gian cho 24k ký tự chỉ vì anh ta phải tính đến kích thước byte thực tế của các ký tự được giới thiệu.
RaptorX

32

Tuyên bố miễn trừ trách nhiệm: Tôi không phải là chuyên gia về MySQL ... nhưng đây là sự hiểu biết của tôi về các vấn đề.

Tôi nghĩ rằng văn bản được lưu trữ bên ngoài hàng mysql, trong khi tôi nghĩ VARCHAR được lưu trữ như một phần của hàng. Có độ dài hàng tối đa cho các hàng mysql .. vì vậy bạn có thể giới hạn số lượng dữ liệu khác bạn có thể lưu trữ trong một hàng bằng cách sử dụng VARCHAR.

Ngoài ra do VARCHAR tạo thành một phần của hàng, tôi nghi ngờ rằng các truy vấn nhìn vào trường đó sẽ nhanh hơn một chút so với các truy vấn sử dụng đoạn văn bản.


38
Giới hạn độ dài hàng là 65.535 byte [ dev.mysql.com/doc/refman/5.0/en/column-count-limit.html ]. Nếu cột của bạn được mã hóa utf8, điều đó có nghĩa là varcharcột 3000 ký tự có thể mất tới 9000 byte.
Jan Fabry

7
Các ký tự UTF-8 có thể lên tới 4 byte, vì vậy tôi nghĩ bạn có nghĩa là 12.000 byte (trừ khi có một số điều MySQL tôi không hiểu ở đây).
raylu

13
@raylu UTF-8 của MySQL là "UTF-8 giả" ở chỗ nó chỉ hỗ trợ tối đa 3 byte cho mỗi ký tự, vì vậy không có cách nào để lưu trữ trực tiếp các ký tự unicode ngoài mặt phẳng BMP trong UTF-8 của MySQL. Điều này được cố định trong MySQL 5.5.
Pacerier

2
Tôi tin rằng khẳng định này chỉ có giá trị với MyISAM. Tôi không thể tìm thấy một nguồn chính xác nhưng tôi tin rằng InnoDB cũng lưu trữ TEXTnội tuyến trong bảng.
dotancohen

2
@dotancohen Tôi đã tìm thấy một nguồn ở đây giải thích rằng việc lưu trữ dữ liệu có độ dài thay đổi bằng InnoDB có thể khác nhau (có thể được lưu trữ bên ngoài hoặc nội tuyến trong hàng) mysqlserverteam.com/externally-stored-fields-in-innodb
KiX Ortillan

30

Câu trả lời ngắn: Không thực tế, hiệu suất, hoặc lưu trữ, sự khác biệt.

Câu trả lời dài:

Về cơ bản không có sự khác biệt (trong MySQL) giữa VARCHAR(3000)(hoặc bất kỳ giới hạn lớn nào khác) và TEXT. Cái trước sẽ cắt ngắn ở 3000 ký tự ; cái sau sẽ cắt ở 65535 byte . (Tôi phân biệt giữa byteký tự vì một ký tự có thể lấy nhiều byte.)

Đối với các giới hạn nhỏ hơn VARCHAR, có một số lợi thế hơn TEXT.

  • "nhỏ hơn" có nghĩa là 191, 255, 512, 767 hoặc 3072, v.v., tùy thuộc vào phiên bản, ngữ cảnh và CHARACTER SET.
  • INDEXesbị giới hạn về mức độ lớn của một cột có thể được lập chỉ mục. (767 hoặc 3072 byte ; đây là phiên bản và cài đặt phụ thuộc)
  • Các bảng trung gian được tạo bởi phức SELECTsđược xử lý theo hai cách khác nhau - NHỚ (nhanh hơn) hoặc MyISAM (chậm hơn). Khi các cột 'lớn' được tham gia, kỹ thuật chậm hơn sẽ tự động được chọn. (Những thay đổi đáng kể trong phiên bản 8.0; vì vậy mục đạn này có thể thay đổi.)
  • Liên quan đến mục trước đó, tất cả các TEXTkiểu dữ liệu (trái ngược với VARCHAR) nhảy thẳng đến MyISAM. Đó là, TINYTEXTtự động tệ hơn cho các bảng tạm thời được tạo ra so với các bảng tương đương VARCHAR. (Nhưng điều này sẽ thảo luận theo hướng thứ ba!)
  • VARBINARYlà như thế VARCHAR; BLOBcũng giống như TEXT.

Từ chối các câu trả lời khác

Câu hỏi ban đầu hỏi một điều (sử dụng kiểu dữ liệu nào); câu trả lời được chấp nhận đã trả lời một cái gì đó khác (lưu trữ ngoài bản ghi). Câu trả lời đó đã hết hạn.

Khi chủ đề này được bắt đầu trả lời, chỉ có hai "định dạng hàng" trong InnoDB. Ngay sau đó, hai định dạng ( DYNAMICCOMPRESSED) đã được giới thiệu.

Vị trí lưu trữ cho TEXTVARCHAR()dựa trên kích thước , không phải tên của kiểu dữ liệu . Để thảo luận cập nhật về lưu trữ trên / ngoài bản ghi của các cột văn bản / blob lớn, hãy xem phần này .


1
Một số cái nhìn sâu sắc tốt ở đây. Đây phải là câu trả lời được chấp nhận.
Kosta Kontos

2
@KostaKontos - Cảm ơn bạn đã khen ngợi và sửa lỗi chính tả. Khi tôi thấy cần một câu trả lời tốt hơn, tôi sẽ thêm một câu trả lời, ngay cả khi 8 năm và 800 lần nâng cấp quá muộn.
Rick James

7

Các câu trả lời trước không nhấn mạnh đủ vào vấn đề chính: ngay cả trong các truy vấn rất đơn giản như

(SELECT t2.* FROM t1, t2 WHERE t2.id = t1.id ORDER BY t1.id) 

một bảng tạm thời có thể được yêu cầu và nếu một VARCHARtrường có liên quan, nó được chuyển đổi thành một CHARtrường trong bảng tạm thời. Vì vậy, nếu trong bảng của bạn có 500 000 dòng với một VARCHAR(65000)trường, riêng cột này sẽ sử dụng 6,5 * 5 * 10 ^ 9 byte. Các bảng tạm thời như vậy không thể được xử lý trong bộ nhớ và được ghi vào đĩa. Tác động có thể được dự kiến ​​là thảm họa.

Nguồn (có số liệu): https://nicj.net/mysql-text-vs-varchar-performance/ (Điều này đề cập đến việc xử lý TEXTvs VARCHARtrong "công cụ lưu trữ MyISAM" tiêu chuẩn "(?). Nó có thể khác ở những người khác, ví dụ: InnoDB.)


3
InnoDB: Áp dụng tương tự thông qua phiên bản 5.7. Với 8.0, temps varchar có chiều dài thay đổi.
Rick James

3

Có một HUGE chênh lệch giữa VARCHAR và TEXT. Trong khi các trường VARCHAR có thể được lập chỉ mục, các trường TEXT không thể. Các trường loại VARCHAR được lưu trữ nội tuyến trong khi văn bản được lưu trữ ngoại tuyến, chỉ các con trỏ tới dữ liệu văn bản thực sự được lưu trữ trong các bản ghi.

Nếu bạn phải lập chỉ mục cho lĩnh vực của mình để tìm kiếm, cập nhật hoặc xóa nhanh hơn so với VARCHAR, bất kể lớn như thế nào. Một VARCHAR (10000000) sẽ không bao giờ giống như trường VĂN vì hai loại dữ liệu này có bản chất khác nhau.

  • Nếu bạn sử dụng trường của bạn chỉ để lưu trữ
  • bạn không quan tâm đến tốc độ dữ liệu
  • bạn quan tâm đến tốc độ nhưng bạn sẽ sử dụng toán tử '% THÍCH%' trong truy vấn tìm kiếm của mình để việc lập chỉ mục sẽ không giúp ích nhiều
  • bạn không thể dự đoán giới hạn về độ dài dữ liệu

hơn là đi cho văn bản.


Thông tin sai lệch một phần: Các cột văn bản không thể được lập chỉ mục trong toàn bộ. Khi bạn bao gồm một cột văn bản trong chỉ mục, bạn phải chỉ định độ dài. Ngoài ra, VARCHAR không thể được lập chỉ mục toàn bộ trong trường hợp VARCHARs> 255 vì có độ dài tối đa trên kích thước chỉ mục.
eRadical

2

Varchar dành cho dữ liệu nhỏ như địa chỉ email, trong khi Văn bản dành cho dữ liệu lớn hơn nhiều như các bài báo, Blob cho dữ liệu nhị phân như hình ảnh.

Hiệu suất của Varchar mạnh hơn vì nó chạy hoàn toàn từ bộ nhớ, nhưng điều này sẽ không xảy ra nếu dữ liệu quá lớn như varchar(4000)ví dụ.

Mặt khác, văn bản không dính vào bộ nhớ và bị ảnh hưởng bởi hiệu suất đĩa, nhưng bạn có thể tránh điều đó bằng cách tách dữ liệu văn bản trong một bảng riêng biệt và áp dụng truy vấn nối trái để lấy dữ liệu văn bản.

Blob chậm hơn rất nhiều vì vậy chỉ sử dụng nó nếu bạn không có nhiều dữ liệu như 10000 hình ảnh sẽ tốn 10000 hồ sơ.

Thực hiện theo các mẹo sau để có tốc độ và hiệu suất tối đa:

  1. Sử dụng varchar cho tên, tiêu đề, email

  2. Sử dụng Văn bản cho dữ liệu lớn

  3. Tách văn bản trong các bảng khác nhau

  4. Sử dụng các truy vấn còn lại Tham gia trên một ID như số điện thoại

  5. Nếu bạn định sử dụng Blob, hãy áp dụng các mẹo tương tự như trong Văn bản

Điều này sẽ khiến các truy vấn có giá mili giây trên các bảng có dữ liệu> 10 M và kích thước lên tới 10GB được đảm bảo.

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.