Czy w SQL Server 2005 występują jakieś wady tworzenia wszystkich pól znakowych nvarchar (MAX) zamiast jawnego podawania długości, np. Nvarchar (255)? (Poza oczywistym, że nie jesteś w stanie ograniczyć długości pola na poziomie bazy danych)
Czy w SQL Server 2005 występują jakieś wady tworzenia wszystkich pól znakowych nvarchar (MAX) zamiast jawnego podawania długości, np. Nvarchar (255)? (Poza oczywistym, że nie jesteś w stanie ograniczyć długości pola na poziomie bazy danych)
Odpowiedzi:
To samo pytanie zadano na forach MSDN:
Z oryginalnego postu (tam więcej informacji):
Gdy przechowujesz dane w kolumnie VARCHAR (N), wartości są fizycznie przechowywane w ten sam sposób. Ale kiedy przechowujesz je w kolumnie VARCHAR (MAX), za ekranem dane są traktowane jako wartość TEXT. Dlatego w przypadku wartości VARCHAR (MAX) konieczne jest dodatkowe przetwarzanie. (tylko jeśli rozmiar przekracza 8000)
VARCHAR (MAX) lub NVARCHAR (MAX) jest uważany za „typ dużej wartości”. Typy dużych wartości są zwykle przechowywane „poza wierszem”. Oznacza to, że wiersz danych będzie miał wskaźnik do innej lokalizacji, w której przechowywana jest „duża wartość” ...
N/VARCHAR(MAX)
”, ponieważ istnieje dodatkowe przetwarzanie „tylko wtedy, gdy rozmiar przekracza 8000”. W związku z tym ponosisz koszty tylko wtedy , gdy jest to konieczne , a twoja baza danych jest mniej restrykcyjna . Czy źle to czytam? Wygląda na to, że prawie zawsze chciałbyś N/VARCHAR(MAX)
zamiast N/VARCHAR(1-8000)
...
sp_tableoptions
: msdn.microsoft.com/en-us/library/ms173530.aspx . Typy VARCHAR (255) można również wypchnąć z wiersza, wspomniany „narzut” może być dokładnie taki sam dla MAX i 255. Porównuje typy MAX z typami TEKSTOWYMI, gdy są one różne w miarę ich uzyskiwania (całkowicie inny interfejs API do manipulowania, inne miejsce do przechowywania itp.). Nie wspomina o rzeczywistych różnicach: brak indeksu, brak operacji online na typach MAX
To uczciwe pytanie, a on stwierdził poza oczywistym…
Wady mogą obejmować:
Wpływ na wydajność Optymalizator kwerend wykorzystuje rozmiar pola do ustalenia najbardziej skutecznego planu egzekwowania
„1. Przydział miejsca w rozszerzeniach i stronach bazy danych jest elastyczny. Dlatego dodając informacje do pola za pomocą aktualizacji, baza danych musiałaby utworzyć wskaźnik, jeśli nowe dane są dłuższe niż poprzednio wstawione. To pliki bazy danych stać się rozdrobnione = niższa wydajność prawie we wszystkim, od indeksu do usuwania, aktualizacji i wstawiania. ” http://sqlblogcasts.com/blogs/simons/archive/2006/02/28/Why-use-anything-but-varchar_2800_max_2900_.aspx
Wpływ na integrację - inne systemy mają trudności z integracją z bazą danych Nieprzewidziany wzrost danych Możliwe problemy z bezpieczeństwem, np. Można zawiesić system, zajmując całe miejsce na dysku
Dobry artykuł tutaj: http://searchsqlserver.techtarget.com/tip/1,289483,sid87_gci1098157,00.html
varchar(max)
.
Na podstawie linku podanego w zaakceptowanej odpowiedzi wydaje się, że:
100 znaków przechowywanych w nvarchar(MAX)
polu będzie przechowywanych nie inaczej niż 100 znaków w nvarchar(100)
polu - dane będą przechowywane w wierszu i nie będziesz mieć narzutu związanego z odczytywaniem i zapisywaniem danych „poza wierszem”. Więc nie martw się.
Jeśli rozmiar jest większy niż 4000, dane byłyby automatycznie zapisywane „poza wierszem”, co byś chciał. Nie martw się też.
Jednak...
nvarchar(MAX)
kolumnie. Możesz użyć indeksowania pełnotekstowego, ale nie można utworzyć indeksu w kolumnie, aby poprawić wydajność zapytania. Dla mnie to uszczelnia umowę ... zdecydowanie wadą jest zawsze używanie nvarchar (MAX).Wniosek:
Jeśli chcesz mieć coś w rodzaju „uniwersalnej długości ciągu” w całej bazie danych, która może być indeksowana i która nie będzie marnować miejsca i czasu dostępu, możesz użyć nvarchar(4000)
.
nvarchar(max)
cały czas - jak string
w C #? - ale punkt 3) (problem z indeksem) daje odpowiedź.
nvarchar(4000)
Czasami chcesz, aby typ danych wymusił pewien sens na danych w nim zawartych.
Powiedzmy na przykład, że masz kolumnę, która tak naprawdę nie powinna być dłuższa niż, powiedzmy, 20 znaków. Jeśli zdefiniujesz tę kolumnę jako VARCHAR (MAX), niektóre nieuczciwe aplikacje mogą wstawić do niej długi ciąg znaków i nigdy byś się nie dowiedział, ani nie mógł w żaden sposób temu zapobiec.
Następnym razem, gdy aplikacja użyje tego ciągu, przy założeniu, że długość łańcucha jest skromna i rozsądna dla reprezentowanej przez niego domeny, wystąpi nieprzewidziany i mylący wynik.
Sprawdziłem kilka artykułów i znalazłem przydatny skrypt testowy z tego: http://www.sqlservercentral.com/Forums/Topic1480639-1292-1.aspx Następnie zmieniłem go, aby porównać NVARCHAR (10) vs NVARCHAR (4000) vs NVARCHAR (MAX ) i nie znajduję różnicy prędkości przy użyciu określonych liczb, ale przy użyciu MAX. Możesz samemu przetestować. Mam nadzieję, że to pomoże.
SET NOCOUNT ON;
--===== Test Variable Assignment 1,000,000 times using NVARCHAR(10)
DECLARE @SomeString NVARCHAR(10),
@StartTime DATETIME;
--=====
SELECT @startTime = GETDATE();
SELECT TOP 1000000
@SomeString = 'ABC'
FROM master.sys.all_columns ac1,
master.sys.all_columns ac2;
SELECT testTime='10', Duration = DATEDIFF(ms,@StartTime,GETDATE());
GO
--===== Test Variable Assignment 1,000,000 times using NVARCHAR(4000)
DECLARE @SomeString NVARCHAR(4000),
@StartTime DATETIME;
SELECT @startTime = GETDATE();
SELECT TOP 1000000
@SomeString = 'ABC'
FROM master.sys.all_columns ac1,
master.sys.all_columns ac2;
SELECT testTime='4000', Duration = DATEDIFF(ms,@StartTime,GETDATE());
GO
--===== Test Variable Assignment 1,000,000 times using NVARCHAR(MAX)
DECLARE @SomeString NVARCHAR(MAX),
@StartTime DATETIME;
SELECT @startTime = GETDATE();
SELECT TOP 1000000
@SomeString = 'ABC'
FROM master.sys.all_columns ac1,
master.sys.all_columns ac2;
SELECT testTime='MAX', Duration = DATEDIFF(ms,@StartTime,GETDATE());
GO
Potraktuj to jako kolejny poziom bezpieczeństwa. Możesz zaprojektować swoją tabelę bez relacji klucza obcego - całkowicie poprawne - i zapewnić istnienie powiązanych jednostek całkowicie na warstwie biznesowej. Jednak klucze obce są uważane za dobrą praktykę projektowania, ponieważ dodają kolejny poziom ograniczenia na wypadek, gdyby coś poszło nie tak w warstwie biznesowej. To samo dotyczy ograniczenia wielkości pola i niestosowania varchar MAX.
Powodem, dla którego NIE należy używać pól maksymalnych lub tekstowych, jest to, że nie można wykonać przebudowy indeksu online, tj. ODBUDUJ ONLINE = WŁĄCZONY, nawet przy SQL Server Enterprise Edition.
Jedynym problemem było to, że znalazłem rozwijamy nasze aplikacje na SQL Server 2005, a w jednym przypadku mamy do wspierania SQL Server 2000. Właśnie dowiedziałem się, w bolesny sposób , że SQL Server 2000 nie lubi opcji MAX dla varchar lub nvarchar.
Zły pomysł, gdy wiesz, że pole będzie w ustawionym zakresie - na przykład od 5 do 10 znaków. Myślę, że użyłbym maksimum tylko wtedy, gdy nie byłem pewien, jaka będzie długość. Na przykład numer telefonu nigdy nie byłby dłuższy niż pewna liczba znaków.
Czy możesz szczerze powiedzieć, że nie masz pewności co do wymagań dotyczących przybliżonej długości każdego pola w tabeli?
Rozumiem twój punkt widzenia - są pewne pola, które z pewnością rozważę użycie varchar (max).
Co ciekawe, dokumenty MSDN całkiem dobrze to podsumowują:
Użyj varchar, gdy rozmiary wpisów danych kolumn znacznie się różnią. Użyj varchar (maks.), Gdy rozmiary wpisów danych w kolumnach znacznie się różnią, a rozmiar może przekraczać 8 000 bajtów.
Tutaj jest ciekawa dyskusja na ten temat .
Zadaniem bazy danych jest przechowywanie danych, aby mogły z nich korzystać przedsiębiorstwa. Częścią uczynienia tych danych użytecznymi jest zapewnienie, że mają one sens. Umożliwienie komuś wpisania nieograniczonej liczby znaków dla imienia nie zapewnia znaczących danych.
Wbudowanie tych ograniczeń w warstwę biznesową jest dobrym pomysłem, ale nie gwarantuje to, że baza danych pozostanie nienaruszona. Jedynym sposobem zagwarantowania, że reguły dotyczące danych nie zostaną naruszone, jest wymuszenie ich na najniższym możliwym poziomie w bazie danych.
Jednym z problemów jest to, że jeśli musisz pracować z wieloma wersjami SQL Server, MAX nie zawsze będzie działać. Więc jeśli pracujesz ze starszymi DB lub inną sytuacją, która dotyczy wielu wersji, lepiej bądź bardzo ostrożny.
Jak wspomniano powyżej, jest to przede wszystkim kompromis między pamięcią masową a wydajnością. Przynajmniej w większości przypadków.
Jest jednak co najmniej jeden inny czynnik, który należy wziąć pod uwagę przy wyborze n / varchar (Max) zamiast n / varchar (n). Czy dane będą indeksowane (np. Nazwisko)? Ponieważ definicja MAX jest uważana za LOB, wszystko zdefiniowane jako MAX nie jest dostępne do indeksowania. i bez indeksu każde wyszukiwanie obejmujące dane jako predykat w klauzuli WHERE będzie zmuszone do skanowania pełnego stołu, co jest najgorszą wydajnością, jaką można uzyskać dla wyszukiwania danych.
1) Serwer SQL będzie musiał zużywać więcej zasobów (przydzielona pamięć i czas procesora) podczas pracy z nvarchar (max) vs nvarchar (n), gdzie n jest liczbą specyficzną dla tego pola.
2) Co to oznacza w odniesieniu do wydajności?
W SQL Server 2005 przeszukałem 13 000 wierszy danych z tabeli zawierającej 15 kolumn nvarchar (max). Wielokrotnie mierzyłem czas zapytań, a następnie zmieniałem kolumny na nvarchar (255) lub mniej.
Kwerendy przed optymalizacją uśredniono na 2,0858 sekund. Zapytania po zmianie powróciły średnio w 1,90 sekundy. To było około 184 milisekund ulepszenia podstawowego zapytania select *. To poprawa o 8,8%.
3) Moje wyniki są zbieżne z kilkoma innymi artykułami wskazującymi na różnicę w wydajności. W zależności od bazy danych i zapytania odsetek ulepszeń może się różnić. Jeśli nie masz wielu równoczesnych użytkowników lub bardzo wielu rekordów, różnica w wydajności nie będzie dla ciebie problemem. Różnica w wydajności wzrośnie jednak wraz ze wzrostem liczby rekordów i jednoczesnych użytkowników.
Miałem udf, który wypełniał napisy i wstawiał wyjście do varchar (max). Jeśli użyto tego bezpośrednio zamiast odlewania z powrotem do odpowiedniego rozmiaru dla dostosowywanej kolumny, wydajność była bardzo słaba. Skończyło się na umieszczeniu udf na dowolnej długości z dużą nutą, zamiast polegać na wszystkich wywołujących udf, aby ponownie rzucić ciąg na mniejszy rozmiar.
Jeśli wszystkie dane w wierszu (dla wszystkich kolumn) nigdy nie zajęłyby rozsądnie 8000 lub mniej znaków, projekt w warstwie danych powinien to wymusić.
Silnik bazy danych jest znacznie wydajniejszy, utrzymując wszystko poza magazynem obiektów blob. Im mniejszy możesz ograniczyć wiersz, tym lepiej. Im więcej wierszy można wcisnąć na stronie, tym lepiej. Baza danych po prostu działa lepiej, gdy musi uzyskać dostęp do mniejszej liczby stron.
Moje testy wykazały, że istnieją różnice przy wyborze.
CREATE TABLE t4000 (a NVARCHAR(4000) NULL);
CREATE TABLE tmax (a NVARCHAR(MAX) NULL);
DECLARE @abc4 NVARCHAR(4000) = N'ABC';
INSERT INTO t4000
SELECT TOP 1000000 @abc4
FROM
master.sys.all_columns ac1,
master.sys.all_columns ac2;
DECLARE @abc NVARCHAR(MAX) = N'ABC';
INSERT INTO tmax
SELECT TOP 1000000 @abc
FROM
master.sys.all_columns ac1,
master.sys.all_columns ac2;
SET STATISTICS TIME ON;
SET STATISTICS IO ON;
SELECT * FROM dbo.t4000;
SELECT * FROM dbo.tmax;
Interesujący link: Po co używać VARCHAR, kiedy można używać TEKSTU?
Chodzi o PostgreSQL i MySQL, więc analiza wydajności jest inna, ale logika „jawności” nadal obowiązuje: po co zmusić się, aby zawsze martwić się o coś, co jest istotne przez krótki czas? Jeśli zapisałeś adres e-mail w zmiennej, użyjesz „łańcucha”, a nie „łańcucha ograniczonego do 80 znaków”.
Główną wadą, jaką widzę, jest to, że powiedzmy, że masz to:
Który zawiera najwięcej informacji o danych potrzebnych do interfejsu użytkownika?
To
CREATE TABLE [dbo].[BusData](
[ID] [int] IDENTITY(1,1) NOT NULL,
[RecordId] [nvarchar](MAX) NULL,
[CompanyName] [nvarchar](MAX) NOT NULL,
[FirstName] [nvarchar](MAX) NOT NULL,
[LastName] [nvarchar](MAX) NOT NULL,
[ADDRESS] [nvarchar](MAX) NOT NULL,
[CITY] [nvarchar](MAX) NOT NULL,
[County] [nvarchar](MAX) NOT NULL,
[STATE] [nvarchar](MAX) NOT NULL,
[ZIP] [nvarchar](MAX) NOT NULL,
[PHONE] [nvarchar](MAX) NOT NULL,
[COUNTRY] [nvarchar](MAX) NOT NULL,
[NPA] [nvarchar](MAX) NULL,
[NXX] [nvarchar](MAX) NULL,
[XXXX] [nvarchar](MAX) NULL,
[CurrentRecord] [nvarchar](MAX) NULL,
[TotalCount] [nvarchar](MAX) NULL,
[Status] [int] NOT NULL,
[ChangeDate] [datetime] NOT NULL
) ON [PRIMARY]
Albo to?
CREATE TABLE [dbo].[BusData](
[ID] [int] IDENTITY(1,1) NOT NULL,
[RecordId] [nvarchar](50) NULL,
[CompanyName] [nvarchar](50) NOT NULL,
[FirstName] [nvarchar](50) NOT NULL,
[LastName] [nvarchar](50) NOT NULL,
[ADDRESS] [nvarchar](50) NOT NULL,
[CITY] [nvarchar](50) NOT NULL,
[County] [nvarchar](50) NOT NULL,
[STATE] [nvarchar](2) NOT NULL,
[ZIP] [nvarchar](16) NOT NULL,
[PHONE] [nvarchar](18) NOT NULL,
[COUNTRY] [nvarchar](50) NOT NULL,
[NPA] [nvarchar](3) NULL,
[NXX] [nvarchar](3) NULL,
[XXXX] [nvarchar](4) NULL,
[CurrentRecord] [nvarchar](50) NULL,
[TotalCount] [nvarchar](50) NULL,
[Status] [int] NOT NULL,
[ChangeDate] [datetime] NOT NULL
) ON [PRIMARY]
Jedną wadą jest to, że będziesz projektować wokół nieprzewidywalnej zmiennej i prawdopodobnie zignorujesz zamiast korzystać z wewnętrznej struktury danych SQL Server, stopniowo składającej się z Wiersza (ów), Strony (stron) i Zakresu (ów).
Co sprawia, że myślę o wyrównaniu struktury danych w C, i że świadomość tego wyrównania jest ogólnie uważana za dobrą rzecz (TM). Podobny pomysł, inny kontekst.
Strona MSDN dla stron i zakresów
Strona MSDN dla danych przepełnienia wiersza
najpierw pomyślałem o tym, ale potem jeszcze raz. Ma to wpływ na wydajność, ale równie dobrze służy jako forma dokumentacji, aby zorientować się, jakie naprawdę są rozmiary pól. I wymusza, gdy ta baza danych znajduje się w większym ekosystemie. Moim zdaniem kluczem jest być pobłażającym, ale tylko w granicach rozsądku.
ok, oto moje odczucia w kwestii logiki biznesowej i warstwy danych. To zależy, jeśli twoja baza danych jest zasobem współdzielonym między systemami, które współużytkują logikę biznesową, to oczywiście wydaje się naturalnym miejscem do egzekwowania takiej logiki, ale to nie jest NAJLEPSZY sposób, aby to zrobić, NAJLEPSZY sposób to zapewnić interfejs API, pozwala testowana interakcja, która utrzymuje logikę biznesową tam, gdzie należy, utrzymuje systemy oddzielone od siebie, utrzymuje warstwy w systemie oddzielonym. Jeśli jednak twoja baza danych ma obsługiwać tylko jedną aplikację, pozwól AGILE pomyśleć, co jest teraz prawdą? projekt na teraz. Jeśli i kiedy taki dostęp jest potrzebny, podaj API tych danych.
oczywiście jest to jednak ideał, jeśli pracujesz z istniejącym systemem, istnieje prawdopodobieństwo, że będziesz musiał to zrobić inaczej, przynajmniej w krótkim okresie.
Spowoduje to problem z wydajnością, chociaż nigdy nie może powodować żadnych faktycznych problemów, jeśli baza danych jest mała. Każdy rekord zajmie więcej miejsca na dysku twardym, a baza danych będzie musiała odczytać więcej sektorów dysku, jeśli przeszukujesz wiele rekordów jednocześnie. Na przykład, mały rekord może zmieścić 50 w sektorze, a duży może zmieścić się w 5. Może być konieczne odczytanie 10 razy więcej danych z dysku za pomocą dużego rekordu.
nvarchar(max)
kolumnie nie zajmuje więcej miejsca na dysku niż w nvarchar(100)
kolumnie.