Tôi ngần ngại để thêm một câu trả lời khác ở đây vì đã có khá nhiều, nhưng một vài điểm cần được thực hiện mà chưa được thực hiện hoặc không được thực hiện rõ ràng.
Thứ nhất: Không phải lúc nào cũng sử dụng NVARCHAR
. Đó là một thái độ / cách tiếp cận rất nguy hiểm và thường tốn kém. Và không có gì tốt hơn để nói " Không bao giờ sử dụng con trỏ" vì đôi khi chúng là phương tiện hiệu quả nhất để giải quyết một vấn đề cụ thể, và công việc chung của việc thực hiện một WHILE
vòng lặp sẽ hầu như luôn chậm hơn so với Con trỏ được thực hiện đúng .
Lần duy nhất bạn nên sử dụng thuật ngữ "luôn luôn" là khi khuyên "luôn luôn làm những gì tốt nhất cho tình huống". Được cho là thường rất khó xác định, đặc biệt là khi cố gắng cân bằng lợi ích ngắn hạn trong thời gian phát triển (người quản lý: "chúng tôi cần tính năng này - mà bạn chưa biết đến cho đến tận bây giờ - một tuần trước!") -Chi phí bảo trì (người quản lý ban đầu gây áp lực cho nhóm để hoàn thành dự án 3 tháng trong giai đoạn nước rút 3 tuần: "tại sao chúng ta gặp phải những vấn đề về hiệu suất này? Làm thế nào chúng ta có thể thực hiện X mà không linh hoạt? chạy nước rút hoặc hai lần để khắc phục điều này. Chúng ta có thể làm gì trong một tuần để có thể quay lại các mục ưu tiên của mình? Và chúng ta chắc chắn cần dành nhiều thời gian hơn cho thiết kế để điều này không xảy ra! ").
Thứ hai: Câu trả lời của @ gbn chạm vào một số điểm rất quan trọng cần xem xét khi đưa ra quyết định mô hình hóa dữ liệu nhất định khi đường dẫn không rõ ràng 100%. Nhưng thậm chí còn nhiều hơn để xem xét:
- kích thước của tệp nhật ký giao dịch
- cần có thời gian để nhân rộng (nếu sử dụng nhân rộng)
- cần có thời gian để ETL (nếu ETLing)
- cần có thời gian để chuyển nhật ký đến một hệ thống từ xa và khôi phục (nếu sử dụng Nhật ký vận chuyển)
- kích thước của bản sao lưu
- thời gian cần thiết để hoàn thành sao lưu
- thời gian cần thiết để khôi phục (điều này có thể quan trọng vào một ngày nào đó ;-)
- kích thước cần thiết cho tempdb
- hiệu suất của các kích hoạt (đối với các bảng được chèn và xóa được lưu trữ trong tempdb)
- hiệu suất của phiên bản hàng (nếu sử dụng SNAPSHOT ISOLATION, vì kho phiên bản nằm trong tempdb)
- khả năng có được dung lượng đĩa mới khi CFO nói rằng họ chỉ chi 1 triệu đô la cho SAN năm ngoái và vì vậy họ sẽ không ủy quyền thêm 250 nghìn đô la nữa cho bộ nhớ bổ sung
- khoảng thời gian cần thiết để thực hiện các thao tác INSERT và UPDATE
- thời gian cần thiết để bảo trì chỉ số
- v.v.
Không gian lãng phí có hiệu ứng tầng lớn trên toàn bộ hệ thống. Tôi đã viết một bài viết đi sâu vào chi tiết rõ ràng về chủ đề này: Đĩa là giá rẻ! ORLY? (yêu cầu đăng ký miễn phí; xin lỗi tôi không kiểm soát chính sách đó).
Thứ ba: Mặc dù một số câu trả lời tập trung không chính xác vào khía cạnh "đây là một ứng dụng nhỏ" và một số câu trả lời chính xác là "sử dụng những gì phù hợp", không có câu trả lời nào cung cấp hướng dẫn thực sự cho OP Một chi tiết quan trọng được đề cập trong Câu hỏi đây có phải là một trang web cho trường học của họ Tuyệt quá! Vì vậy, chúng tôi có thể đề nghị rằng:
- Các lĩnh vực cho tên sinh viên và / hoặc Khoa có lẽ nên
NVARCHAR
vì, theo thời gian, chỉ có nhiều khả năng tên từ các nền văn hóa khác sẽ xuất hiện ở những nơi đó.
- Nhưng đối với địa chỉ đường phố và tên thành phố? Mục đích của ứng dụng không được nêu rõ (nó sẽ hữu ích) nhưng giả sử các bản ghi địa chỉ, nếu có, chỉ liên quan đến một khu vực địa lý cụ thể (nghĩa là một ngôn ngữ / văn hóa), sau đó sử dụng
VARCHAR
với Trang Mã thích hợp (mà được xác định từ Collation của trường).
- Nếu lưu trữ mã ISO của Bang và / hoặc Quốc gia (không cần lưu trữ
INT
/ TINYINT
vì mã ISO có độ dài cố định, con người có thể đọc được và tốt, tiêu chuẩn :) sử dụng CHAR(2)
cho hai mã chữ cái và CHAR(3)
nếu sử dụng 3 mã chữ cái. Và xem xét sử dụng Collation nhị phân như Latin1_General_100_BIN2
.
- Nếu lưu trữ mã bưu chính (ví dụ mã zip), hãy sử dụng
VARCHAR
vì đó là tiêu chuẩn quốc tế để không bao giờ sử dụng bất kỳ chữ cái nào ngoài AZ. Và có, vẫn sử dụng VARCHAR
ngay cả khi chỉ lưu trữ mã zip của Hoa Kỳ chứ không phải INT vì mã zip không phải là số, chúng là chuỗi và một số trong số chúng có số "0" hàng đầu. Và xem xét sử dụng Collation nhị phân như Latin1_General_100_BIN2
.
- Nếu lưu trữ địa chỉ email và / hoặc URL, hãy sử dụng
NVARCHAR
vì cả hai địa chỉ này hiện có thể chứa các ký tự Unicode.
- và như thế....
Thứ tư: Bây giờ bạn có NVARCHAR
dữ liệu chiếm gấp đôi dung lượng cần thiết cho dữ liệu vừa vặn VARCHAR
("vừa vặn" = không biến thành "?") Và bằng cách nào đó, như thể bằng phép thuật, ứng dụng đã phát triển và hiện có hàng triệu bản ghi trong ít nhất một trong các trường trong đó hầu hết các hàng là ASCII tiêu chuẩn nhưng một số có chứa các ký tự Unicode để bạn phải giữ NVARCHAR
, hãy xem xét các điều sau:
Nếu bạn đang sử dụng SQL Server 2008 - 2016 RTM và đang ở Phiên bản doanh nghiệp, HOẶC nếu sử dụng SQL Server 2016 SP1 (giúp nén dữ liệu có sẵn trong tất cả các phiên bản) hoặc mới hơn, thì bạn có thể bật Nén dữ liệu . Nén dữ liệu có thể (nhưng sẽ không "luôn luôn") nén dữ liệu Unicode trong NCHAR
và NVARCHAR
các trường. Các yếu tố quyết định là:
NCHAR(1 - 4000)
và NVARCHAR(1 - 4000)
sử dụng Lược đồ nén tiêu chuẩn cho Unicode , nhưng chỉ bắt đầu trong SQL Server 2008 R2, và chỉ cho dữ liệu IN ROW, chứ không phải QUÁ LỚN! Điều này dường như tốt hơn thuật toán nén ROW / PAGE thông thường.
NVARCHAR(MAX)
và XML
(và tôi cũng đoán VARBINARY(MAX)
, TEXT
và NTEXT
) dữ liệu đó là TRÊN ROW (không tắt hàng trong LOB hoặc OVERFLOW trang) ít nhất có thể TRANG nén, nhưng không Row nén. Tất nhiên, nén PAGE phụ thuộc vào kích thước của giá trị liên tiếp: Tôi đã thử nghiệm với VARCHAR (MAX) và thấy rằng hàng 6000 ký tự / byte sẽ không nén, nhưng hàng 4000 ký tự / byte đã làm.
- Bất kỳ dữ liệu ROW TẮT, LOB hoặc QUÁ LỚN = Không nén cho bạn!
Nếu sử dụng SQL Server 2005 hoặc 2008 - 2016 RTM và không phải trên Phiên bản doanh nghiệp, bạn có thể có hai trường: một VARCHAR
và một NVARCHAR
. Ví dụ: giả sử bạn đang lưu trữ các URL chủ yếu là tất cả các ký tự ASCII cơ bản (giá trị 0 - 127) và do đó phù hợp với VARCHAR
, nhưng đôi khi có các ký tự Unicode. Lược đồ của bạn có thể bao gồm 3 trường sau:
...
URLa VARCHAR(2048) NULL,
URLu NVARCHAR(2048) NULL,
URL AS (ISNULL(CONVERT(NVARCHAR([URLa])), [URLu])),
CONSTRAINT [CK_TableName_OneUrlMax] CHECK (
([URLa] IS NOT NULL OR [URLu] IS NOT NULL)
AND ([URLa] IS NULL OR [URLu] IS NULL))
);
Trong mô hình này, bạn chỉ CHỌN từ [URL]
cột được tính toán. Để chèn và cập nhật, bạn xác định trường nào sẽ sử dụng bằng cách xem nếu chuyển đổi có làm thay đổi giá trị đến hay không, phải là NVARCHAR
loại:
INSERT INTO TableName (..., URLa, URLu)
VALUES (...,
IIF (CONVERT(VARCHAR(2048), @URL) = @URL, @URL, NULL),
IIF (CONVERT(VARCHAR(2048), @URL) <> @URL, NULL, @URL)
);
Bạn có thể GZIP các giá trị đến vào VARBINARY(MAX)
và sau đó giải nén trên đường ra:
- Đối với SQL Server 2005 - 2014: bạn có thể sử dụng SQLCLR. SQL # (thư viện SQLCLR mà tôi đã viết) đi kèm với Util_GZip và Util_GUnzip trong phiên bản miễn phí
- Đối với SQL Server 2016 trở lên: bạn có thể sử dụng các hàm
COMPRESS
và DECOMPRESS
hàm tích hợp, cũng là GZip.
Nếu sử dụng SQL Server 2017 hoặc mới hơn, bạn có thể xem xét việc tạo bảng thành Chỉ mục cột phân cụm.
Mặc dù đây chưa phải là một tùy chọn khả thi, SQL Server 2019 giới thiệu hỗ trợ riêng cho UTF-8 in VARCHAR
/ CHAR
datatypes. Hiện tại có quá nhiều lỗi với nó để sử dụng, nhưng nếu chúng đã được sửa, thì đây là một tùy chọn cho một số tình huống. Vui lòng xem bài đăng của tôi, " Hỗ trợ UTF-8 bản địa trong SQL Server 2019: Tiên tri cứu rỗi hay sai? ", Để biết phân tích chi tiết về tính năng mới này.