varchar (max) ở mọi nơi?


80

Có vấn đề gì với việc tạo tất cả các cột chuỗi trong Sql Server 2008 của bạn là varchar (max) không? Các kích thước chuỗi cho phép của tôi được ứng dụng quản lý. Cơ sở dữ liệu chỉ nên duy trì những gì tôi cung cấp cho nó. Tôi sẽ thực hiện một cú đánh hiệu suất bằng cách khai báo tất cả các cột chuỗi là loại varchar (max) trong Sql Server 2008, bất kể kích thước của dữ liệu thực sự đi vào chúng là bao nhiêu?


1
Trong bài đọc của tôi, nó có vẻ giống như các cột varchar của Máy chủ Sql 'tự động kích thước'. Vì vậy, không phải cột varchar (max) trong đó độ dài tối đa của bất kỳ giá trị nhất định nào là 20 sẽ giống với cột varchar (20)?
BowserKingKoopa

Câu trả lời:


48

Bằng cách sử dụng, VARCHAR(MAX)về cơ bản bạn đang nói với SQL Server "lưu trữ các giá trị trong trường này theo cách bạn thấy tốt nhất", SQL Server sau đó sẽ chọn lưu trữ các giá trị dưới dạng thông thường VARCHARhay dưới dạng LOB (Đối tượng lớn). Nói chung, nếu các giá trị được lưu trữ nhỏ hơn 8.000 byte, SQL Server sẽ coi các giá trị là một VARCHARloại thông thường .

Nếu các giá trị được lưu trữ quá lớn thì cột được phép tràn ra ngoài trang trong để trang LOB, chính xác như họ làm với nhiều loại LOB khác ( text, ntextimage) - nếu điều này xảy ra thì trang thêm nội dung đã được yêu cầu phải đọc dữ liệu lưu trữ trong các trang bổ sung (tức là có một phần trình diễn), tuy nhiên điều này chỉ xảy ra nếu các giá trị được lưu trữ quá lớn .

Trên thực tế, trong SQL Server 2008 hoặc mới hơn, dữ liệu có thể tràn sang các trang bổ sung ngay cả với các kiểu dữ liệu có độ dài cố định (ví dụ VARCHAR(3,000)), tuy nhiên các trang này được gọi là trang dữ liệu tràn hàng và được xử lý hơi khác.

Phiên bản ngắn: từ góc độ lưu trữ, không có bất lợi khi sử dụng VARCHAR(MAX)hết VARCHAR(N)đối với một số người N.

(Lưu ý rằng điều này cũng áp dụng cho các loại trường có độ dài thay đổi khác NVARCHARVARBINARY)

FYI - Bạn không thể tạo chỉ mục trên VARCHAR(MAX)các cột


Điều này có thể chỉ đúng đối với các trường có giá trị rỗng. Mỗi cột varchar (tối đa) hoặc nvarchar (tối đa) không null yêu cầu 24 byte phân bổ cố định bổ sung. docs.microsoft.com/en-us/sql/t-sql/data-types/…
Liazy

33

Chỉ mục không được rộng hơn 900 byte cho một. Vì vậy, bạn có thể không bao giờ có thể tạo một chỉ mục. Nếu dữ liệu của bạn nhỏ hơn 900 byte, hãy sử dụng varchar (900).

Đây là một nhược điểm: bởi vì nó cho

  • hiệu suất tìm kiếm thực sự tệ
  • không có ràng buộc duy nhất

Nhưng nếu cột varchar (max) không có bất kỳ giá trị nào lớn hơn 900 byte? Sau đó nó sẽ lập chỉ mục? Tôi bối rối vì rất nhiều thứ tôi đang đọc làm cho các loại cột varchar giống như chúng tự động kích thước tối đa khi dữ liệu được nhập vào. Điều này sẽ là hoàn hảo cho những gì tôi muốn, bởi vì ứng dụng sẽ quyết định mức tối đa, không phải cơ sở dữ liệu.
BowserKingKoopa

3
Bạn sẽ nhận được cảnh báo khi bạn tạo chỉ mục và lỗi khi bạn cố gắng chèn> 900. Nhưng nếu dữ liệu của bạn luôn <900, tại sao không sử dụng 900? Có, chúng được lưu trữ dưới dạng chuỗi có độ dài thay đổi.
gbn

8
Tôi không biết liệu dữ liệu của mình có luôn <900 hay không. Đó là mối quan tâm về logic nghiệp vụ. Nếu quy tắc đó thay đổi, tôi nên thay đổi nó trong logic kinh doanh. Tôi cũng không cần phải thay đổi cơ sở dữ liệu. Đó là mục tiêu của tôi dù sao. Để xem liệu tôi có thể thoát khỏi mối quan tâm về kích thước chuỗi ra khỏi cơ sở dữ liệu mà không có hiệu suất đáng chú ý hay không.
BowserKingKoopa

2
Mức độ hữu ích khi lập chỉ mục một cột văn bản dài? Thậm chí có đáng giá để lập chỉ mục một cái gì đó như cột varchar (200) không? Rốt cuộc, bản thân chỉ mục sẽ không hiệu quả. Nhu cầu tìm kiếm trên các "trận đấu chính xác" dài dường như không thể. Và các tìm kiếm theo mẫu sẽ chỉ có lợi nếu biết điểm bắt đầu của mẫu.
Vỡ mộng vào

9

Simon Sabin đã viết một bài về điều này một thời gian trước. Tôi không có thời gian để lấy nó ngay bây giờ, nhưng bạn nên tìm kiếm nó, vì anh ấy đưa ra kết luận rằng bạn không nên sử dụng varchar (max) theo mặc định.

Đã chỉnh sửa: Simon có một vài bài đăng về varchar (max). Các liên kết trong các bình luận bên dưới cho thấy điều này khá độc đáo. Tôi nghĩ điều quan trọng nhất là http://sqlblogcasts.com/blogs/simons/archive/2009/07/11/String-concatenation-with-max-types-stops-plan-caching.aspx , nói về hiệu ứng của varchar (max) trên bộ nhớ đệm kế hoạch. Nguyên tắc chung là phải cẩn thận. Nếu bạn không cần nó là tối đa, thì đừng sử dụng tối đa - nếu bạn cần hơn 8000 ký tự, thì chắc chắn ... hãy sử dụng nó.




Cái đầu tiên. Bởi OMG Ponies.
Rob Farley

Xin lỗi, tôi không có thời gian để tìm liên kết thực sự, tôi đang chuẩn bị bước vào một cuộc họp và tôi muốn bỏ qua câu trả lời.
Rob Farley


6

Đối với câu hỏi này cụ thể một số điểm tôi không thấy đề cập.

  1. Vào 2005/2008/2008 R2 nếu một cột LOB được bao gồm trong một chỉ mục, điều này sẽ chặn việc xây dựng lại chỉ mục trực tuyến.
  2. Vào năm 2012, hạn chế xây dựng lại chỉ mục trực tuyến được dỡ bỏ nhưng các cột LOB không thể tham gia vào chức năng mới Thêm KHÔNG NULL Cột làm Hoạt động Trực tuyến .
  3. Các khóa có thể được lấy ra lâu hơn trên các hàng chứa các cột của kiểu dữ liệu này. ( còn nữa )

Một vài lý do khác được đề cập trong câu trả lời của tôi là tại sao không phải varchar(8000)ở mọi nơi .

  1. Các truy vấn của bạn có thể kết thúc bằng việc yêu cầu cấp bộ nhớ lớn mà không hợp lý với kích thước của dữ liệu.
  2. Trên bảng có trình kích hoạt, nó có thể ngăn chặn tối ưu hóa khi thẻ lập phiên bản không được thêm vào.

5

Tôi đã hỏi câu hỏi tương tự trước đó. nhận được một số câu trả lời thú vị. kiểm tra nó ở đây Có một trang web có một người nói về tác hại của việc sử dụng các cột rộng, tuy nhiên nếu dữ liệu của bạn bị giới hạn trong ứng dụng, thử nghiệm của tôi đã bác bỏ điều đó. Thực tế là bạn không thể tạo chỉ mục trên các cột có nghĩa là tôi sẽ không sử dụng chúng mọi lúc (cá nhân tôi sẽ không sử dụng chúng nhiều như vậy, nhưng tôi hơi thuần túy về vấn đề đó). Tuy nhiên, nếu bạn biết rằng không có nhiều thứ được lưu trữ trong chúng, tôi không nghĩ chúng tệ như vậy. Nếu bạn thực hiện bất kỳ việc sắp xếp nào trên các cột trong tập bản ghi có varchar (max) trong đó (hoặc bất kỳ cột rộng nào là char hoặc varchar), thì bạn có thể bị phạt về hiệu suất. những điều này có thể được giải quyết (nếu cần) bởi các chỉ mục, nhưng bạn không thể đặt các chỉ mục trên varchar (max). Nếu bạn muốn chứng minh các cột của mình trong tương lai, tại sao không đặt chúng vào một cái gì đó hợp lý. ví dụ cột tên có 255 ký tự thay vì tối đa ...


2

Có một lý do khác để tránh sử dụng varchar (max) trên tất cả các cột. Vì lý do tương tự, chúng tôi sử dụng các ràng buộc kiểm tra (để tránh lấp đầy bảng với rác do phần mềm hoặc người dùng nhập sai gây ra), chúng tôi muốn đề phòng bất kỳ quy trình bị lỗi nào bổ sung nhiều dữ liệu hơn dự định. Ví dụ: nếu ai đó hoặc thứ gì đó cố gắng thêm 3.000 byte vào trường Thành phố, chúng tôi sẽ biết chắc chắn rằng có điều gì đó không ổn và sẽ muốn dừng quá trình chết theo dõi của nó để gỡ lỗi nó vào thời điểm sớm nhất có thể. Chúng tôi cũng biết rằng một tên thành phố 3000 byte có thể không hợp lệ và sẽ làm rối tung các báo cáo và như vậy nếu chúng tôi cố gắng sử dụng nó.


1

Tốt nhất, bạn chỉ nên cho phép những gì bạn cần. Có nghĩa là nếu bạn chắc chắn một cột cụ thể (ví dụ cột tên người dùng) sẽ không bao giờ dài hơn 20 ký tự, việc sử dụng VARCHAR (20) so với VARCHAR (MAX) cho phép cơ sở dữ liệu tối ưu hóa các truy vấn và cấu trúc dữ liệu.

Từ MSDN: http://msdn.microsoft.com/en-us/library/ms176089.aspx

Variable-length, non-Unicode character data. n can be a value from 1 through 8,000. max indicates that the maximum storage size is 2^31-1 bytes.

Bạn có thực sự sẽ đến gần 2 ^ 31-1 byte cho các cột này không?


3
Tôi không nghĩ việc mô tả điều này là "phân bổ" là chính xác. DB chắc chắn không thực sự dành cho bạn 2 ^ 31-1 byte ở bất kỳ đâu.
Scott Stafford

1
"cột tên người dùng [..] sẽ không bao giờ dài hơn 20 ký tự" - Tốt thôi, cho đến một ngày khách hàng quyết định cần dài hơn. Tất cả chúng tôi đã ở đó. :)
Steve Smith
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.