Kod EF Najpierw używa nvarchar (max) dla wszystkich łańcuchów. Czy to pogorszy wydajność zapytania?

29

Mam kilka baz danych utworzonych za pomocą Entity Framework Code First; aplikacje działają i ogólnie jestem całkiem zadowolony z tego, co pozwala mi Code First. Najpierw jestem programistą, a po drugie DBA. Czytam o DataAttributes, aby dalej opisać w C #, co chcę, aby baza danych zrobiła; a moje pytanie brzmi: jaką karę będę jadł, mając te nvarchar(max)łańcuchy na stole (patrz przykład poniżej)?

W tej konkretnej tabeli znajduje się kilka kolumn; w języku C # są one zdefiniowane jako takie:

    [Key]
    [DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
    public int ID { get; set; }
    public string Name { get; set; }
    public string Message { get; set; }
    public string Source { get; set; }
    public DateTime Generated { get; set; }
    public DateTime Written { get; set; }

Oczekuję zapytania i / lub sortowania na podstawie nazwy, źródła, wygenerowanego i zapisanego. Oczekuję, że Nazwa i Źródło będą miały długość 0-50 znaków, czasami nawet do 150. Spodziewam się, że ta tabela zacznie być dość mała (<100 tys. Rzędów), ale z czasem znacznie wzrośnie (> 1m wierszy). Oczywiście wiadomość może być mała lub duża i prawdopodobnie nie będzie się o nią pytać.

Chcę wiedzieć, czy w mojej kolumnie Nazwa i Źródło zdefiniowano trafienie wydajnościowe, nvarchar(max)gdy nigdy nie oczekuję, że będą miały więcej niż 150 znaków?

Nate
źródło
5
Wygląda na to, że musisz zastosować jeden z nich [MaxLength]lub [StringLength]atrybuty. Niektóre dodatkowe możliwe negatywne czynniki zbyt szerokich kolumn są wymienione w odpowiedzi @ PaulWhite tutaj
Martin Smith,
3
TAK , używanie varchar(max)wszędzie szkodzi Twojej wydajności - nie rób tego! Używaj odpowiednich typów danych - używaj varchar(max) TYLKO, jeśli NAPRAWDĘ potrzebujesz więcej niż 8000 znaków! (Nigdy nie widziałem, aby imię i adres e-mail osoby były tak długie!) - Zobacz, jaki jest sens używania VARCHAR (n)? po więcej informacji
marc_s,
@marc_s Świetny link. Wiem, że to szkodzi wydajności. Kiedy definiuję własne tabele za pomocą SQL, używam varchar (n). Moje pytanie dotyczyło bardziej tego, jak bardzo szkodzi to wydajności (choć zdaję sobie sprawę, że nie było to wyraźnie jasne).
Nate
Łącze robocze - jaki jest sens używania VARCHAR (n)?
GFoley83

Odpowiedzi:

24

Większe elementy danych nvarchar (maksymalnie) (ponad 8000 bajtów) zostaną przeniesione do pamięci tekstowej i będą wymagały dodatkowych operacji we / wy. Mniejsze przedmioty będą przechowywane w rzędzie. Istnieją opcje kontrolujące to zachowanie - więcej informacji można znaleźć w tym artykule MSDN .

Jeśli są przechowywane w rzędzie, nie ma znaczącego obciążenia wydajności we / wy; przetwarzanie danych może wiązać się z dodatkowym obciążeniem procesora, ale może to być niewielkie.

Jednak pozostawienie kolumn nvarchar (max) leżących wokół bazy danych, gdzie nie są one potrzebne, jest raczej kiepską formą. Ma pewien narzut wydajności i często rozmiary danych są bardzo pomocne w zrozumieniu tabeli danych - na przykład kolumna varchar o szerokości 50 lub 100 znaków może być opisem lub polem tekstowym, w którym (powiedzmy) 10- 20 znaków może być kodem. Zdziwiłbyś się, jak duże znaczenie ma to na podstawie bazy danych przy takich założeniach.

Praca w hurtowni danych, tak często, jak w słabo obsługiwanych lub udokumentowanych starszych systemach, posiadanie łatwego do zrozumienia schematu bazy danych jest dość cenna. Jeśli uważasz, że baza danych jest dziedzictwem aplikacji, postaraj się być miły dla osób, które odziedziczą ją po tobie.

ConcernedOfTunbridgeWells
źródło
18

Chociaż to nie odpowiada na konkretne pytanie, może to uniemożliwić zadanie pytania: Możliwe jest ustawienie długości zmiennych łańcuchowych w klasie modelu C #, co spowoduje, że Entity Framework wygeneruje SQL, który używa typu nvarchar o stałej długości (np. nvarchar(50)) zamiast nvarchar(max).

Na przykład zamiast:

public string Name { get; set; }

Możesz użyć:

[StringLength(50)]
public string Name { get; set; }

Możesz również wymusić, aby typ był varcharzamiast nvarchar, w razie potrzeby, w następujący sposób:

[Column(TypeName = "VARCHAR")]
[StringLength(50)]
public string Name { get; set; }

Źródło: https://stackoverflow.com/questions/7341783/entity-framework-data-annotations-set-stringlength-varchar/7341920

Jon Schneider
źródło
2
Znalezienie tej odpowiedzi zajęło mi ustalenie, że EF Core obsługuje ustawienie typu i długości w tym samym czasie ( varchar(50)), ale EF 6 wymaga tego, co jest w tej odpowiedzi.
Sinjai
9

Indeksowanie największego problemu. Z BOL:

Kolumny, które są z dużego obiektu (LOB) typów danych ntext, text, varchar(max), nvarchar(max), varbinary(max), xml, lub imagenie może być określona jako kolumny klucz dla indeksu.

Jeśli nie możesz poprawnie indeksować, będziesz mieć wolne zapytania. A z punktu widzenia integralności danych nvarchar(max)pozwolenie na umieszczenie większej ilości złych danych w polu niż określenie limitu byłoby.

HLGEM
źródło
9

Tak, domyślne zachowanie EF w odwzorowaniu stringna nvarchar(max)nie jest dobre. W EF 6 możesz dodać własną niestandardową konwencję, aby zastąpić to zachowanie własnym preferowanym domyślnym odwzorowaniem.

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
    modelBuilder.Properties<string>()
        .Configure(s => s.HasMaxLength(200).HasColumnType("varchar") );

    base.OnModelCreating(modelBuilder);
}

Przesłonięcie OnModelCreatingjak wyżej spowoduje zmianę domyślnego odwzorowania dla wszystkich łańcuchów na varchar(200).

Paweł
źródło
1
To nie działa w EF Core 1.0
Shittu Joseph Olugbenga
the default EF behavior in mapping string to nvarchar(max) is not goodto wydaje się być twoją ogólną opinią. możesz wyjaśnić, dlaczego to nie jest dobre? A może uważasz, że EF nie jest strukturą dla aplikacji biznesowych, w których musisz pracować z wieloma językami? Ponieważ jest to pożądany typ kolumny do obsługi wielu języków w bazie danych.
Matthias Burger,
1
@MatthiasBurger nvarchar (max) jest straszny pod względem wydajności, szczególnie w środowisku replikowanym. To nie jest ogólna opinia, to dobrze znany fakt.
user2966445
@ user2966445 przepraszam, myślę, że było nieporozumienie :) na pewno maxjest okropne. Ale jeśli chcesz obsługiwać wiele języków (i ich różne zestawy znaków), musisz ich użyć, nvarcharczy się mylę?
Matthias Burger
@MatthiasBurger To prawda, użyj nvarchar do różnych zestawów znaków, ale cały ten post dotyczy wydajności i długości pól, a nie użycia nvarchar vs. varchar.
user2966445