Я вагаюся, щоб додати ще одну відповідь тут, оскільки їх уже досить багато, але потрібно зробити кілька моментів, які або не були зроблені, або не були зроблені чітко.
По- перше: Do НЕ завжди використовувати NVARCHAR
. Це дуже небезпечне і часто затратне ставлення / підхід. І не краще сказати " Ніколи не використовуйте курсори", оскільки вони іноді є найбільш ефективним засобом вирішення певної проблеми, і загальна робота навколо WHILE
циклу майже завжди буде повільнішою, ніж правильно виконаний Курсор.
Єдиний час, коли ви повинні використовувати термін «завжди», - це, коли радить «завжди робити те, що найкраще для ситуації». Зазначимо, що часто важко визначити, особливо, коли намагаються збалансувати короткочасні вигоди у часі розвитку (менеджер: "нам потрібна ця функція - про яку ти досі не знав - тиждень тому!") З довгими -строкові витрати на обслуговування (менеджер, який спочатку тиснув на команду, щоб виконати тримісячний проект у 3-тижневому спринті: "чому у нас виникають ці проблеми з продуктивністю? Як ми могли зробити X, який не має гнучкості? Ми не можемо собі дозволити спринт або два, щоб виправити це. Що ми можемо зробити за тиждень, щоб ми могли повернутися до наших пріоритетних пунктів? І нам, безумовно, потрібно витратити більше часу на дизайн, щоб це не продовжувалося! ").
По-друге: відповідь @ gbn стосується деяких дуже важливих моментів, які слід враховувати при прийнятті певних рішень щодо моделювання даних, коли шлях не є на 100% зрозумілим. Але є ще більше, що слід врахувати:
- розмір файлів журналу транзакцій
- час, необхідний для копіювання (якщо використовується реплікація)
- час, який потрібно на ETL (якщо ETLing)
- час, який потрібен для доставки журналів до віддаленої системи та відновлення (якщо використовується журнал доставки)
- розмір резервного копіювання
- проміжок часу, необхідний для завершення резервного копіювання
- тривалість часу, необхідного для відновлення (це може бути важливо одного дня ;-)
- розмір, необхідний для tempdb
- виконання тригерів (для вставлених та видалених таблиць, які зберігаються у tempdb)
- виконання версії версій (якщо використовується SNAPSHOT ISOLATION, оскільки сховище версій знаходиться в tempdb)
- можливість отримати новий дисковий простір, коли фінансовий директор каже, що щойно вони витратили 1 мільйон доларів на SAN в минулому році, і тому вони не дозволять отримати ще $ 250 000 для додаткового зберігання
- тривалість часу, необхідного для виконання INSERT та UPDATE операцій
- тривалість часу, необхідний для обслуговування індексу
- тощо, тощо, і т.д.
Витрата місця має величезний каскадний ефект на всю систему. Я написав статтю з чіткими деталями на цю тему: Диск дешевий! ORLY? (потрібна безкоштовна реєстрація; вибачте, я не контролюю цю політику).
По-третє: Хоча деякі відповіді неправильно зосереджуються на аспекті "це невелика програма", а деякі правильно пропонують "використовувати те, що підходить", жодна з відповідей не дала реальних вказівок до ОП. Важлива деталь, зазначена у запитанні це те, що це веб-сторінка для їхньої школи. Чудово! Тож ми можемо запропонувати:
- Поля для імен студентів та / або викладачів, мабуть, мають бути,
NVARCHAR
оскільки з часом стає лише ймовірніше, що в цих місцях з’являться імена інших культур.
- Але для адреси вулиць та назв міст? Мета програми не була вказана (це було б корисно), але якщо припустити, що записи адрес, якщо такі є, стосуються лише певного географічного регіону (тобто єдиної мови / культури), то використовуйте
VARCHAR
відповідну кодову сторінку (яка визначається із зіставлення поля).
- Якщо ви зберігаєте коди штату та / або країни ISO (не потрібно зберігати
INT
/ TINYINT
оскільки ISO-коди мають фіксовану довжину, читати людину, і, звичайно, стандарт :), використовуйте CHAR(2)
для двох буквених кодів та CHAR(3)
якщо використовуєте 3 буквених коду. І подумайте про використання двійкового зібрання типу Latin1_General_100_BIN2
.
- Якщо ви зберігаєте поштові індекси (тобто поштові індекси), використовуйте,
VARCHAR
оскільки це міжнародний стандарт, щоб ніколи не використовувати жоден лист за межами AZ. І так, все-таки використовувати VARCHAR
навіть якщо зберігати поштові індекси США, а не INT, оскільки поштові індекси не є цифрами, вони є рядками, а деякі з них мають провідне "0". І подумайте про використання двійкового зібрання типу Latin1_General_100_BIN2
.
- Якщо ви зберігаєте адреси електронної пошти та / або URL-адреси, використовуйте,
NVARCHAR
оскільки вони можуть містити символи Unicode.
- і так далі....
Четверте: Тепер, коли у вас є NVARCHAR
дані, що займають вдвічі більше місця, ніж потрібно для даних, які гарно вписуються VARCHAR
("добре вписується" = не перетворюється на "?") І якось, як за допомогою магії, додаток зростає і тепер є мільйони записів принаймні в одному з цих полів, де більшість рядків є стандартними ASCII, але деякі містять символи Unicode, тому вам доведеться зберегти NVARCHAR
, врахуйте наступне:
Якщо ви використовуєте RTM SQL Server 2008 - 2016 і перебуваєте на Enterprise Edition, АБО якщо ви використовуєте SQL Server 2016 SP1 (який зробив стиснення даних доступним у всіх виданнях) або новішим, ви можете ввімкнути стиснення даних . Стиснення даних може (але не "завжди") стискати дані Unicode у NCHAR
та NVARCHAR
полях. Визначальними чинниками є:
NCHAR(1 - 4000)
і NVARCHAR(1 - 4000)
використовуйте Стандартну схему стиснення для Unicode , але починаючи лише з SQL Server 2008 R2, І тільки для даних IN ROW, а не ЗОВНІШНЬО! Здається, це краще, ніж звичайний алгоритм стиснення ROW / PAGE.
NVARCHAR(MAX)
і XML
(і, мабуть, також VARBINARY(MAX)
, TEXT
і NTEXT
) дані, які є В РАДУ (не в рядку на сторінках LOB або OVERFLOW), можна принаймні стискати PAGE, але не стискати ROW. Звичайно, стиснення PAGE залежить від розміру значення рядка: я протестував VARCHAR (MAX) і побачив, що 6000 рядків / байтових рядків не стискатимуться, але 4000 рядків / байт рядків.
- Будь-які дані OFF ROW, LOB або OVERLOW = Без стиснення для вас!
Якщо ви використовуєте RTM SQL Server 2005 або 2008 - 2016, а не в Enterprise Edition, у вас можуть бути два поля: одне VARCHAR
і одне NVARCHAR
. Наприклад, скажімо, що ви зберігаєте URL-адреси, які в основному всі базові символи ASCII (значення 0 - 127) і, отже, вписуються VARCHAR
, але іноді мають символи Unicode. Ваша схема може містити такі 3 поля:
...
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))
);
У цій моделі ви вибрали лише[URL]
обчислений стовпець. Для вставки та оновлення ви визначаєте, яке поле використовувати, бачачи, чи перетворення змінює вхідне значення, яке має бути NVARCHAR
типу:
INSERT INTO TableName (..., URLa, URLu)
VALUES (...,
IIF (CONVERT(VARCHAR(2048), @URL) = @URL, @URL, NULL),
IIF (CONVERT(VARCHAR(2048), @URL) <> @URL, NULL, @URL)
);
Ви можете GZIP вхідні значення в, VARBINARY(MAX)
а потім розпаковувати на виході:
- Для SQL Server 2005 - 2014: ви можете використовувати SQLCLR. SQL # (бібліотека SQLCLR, яку я писав) постачається з Util_GZip та Util_GUnzip у безкоштовній версії
- Для SQL Server 2016 і новіших: ви можете використовувати вбудовані
COMPRESS
та DECOMPRESS
функції, які також є GZip.
Якщо ви використовуєте SQL Server 2017 або новішу версію, ви можете розглянути, як зробити таблицю індексом кластерних стовпців.
Хоча це ще не є життєздатним варіантом, SQL Server 2019 представляє вбудовану підтримку UTF-8 в VARCHAR
/ CHAR
типах даних. Наразі в ньому занадто багато помилок, щоб їх можна було використовувати, але якщо вони виправлені, то це варіант для деяких сценаріїв. Перегляньте мій пост " Native UTF-8 підтримка в SQL Server 2019: рятівник чи помилковий пророк? ", Щоб отримати детальний аналіз цієї нової функції.