Il codice EF utilizza innanzitutto nvarchar (max) per tutte le stringhe. Questo danneggerà le prestazioni delle query?


29

Ho creato alcuni database usando prima Entity Framework Code; le app funzionano e in generale sono abbastanza contento di ciò che Code First mi permette di fare. Per prima cosa sono un programmatore e un secondo DBA. Sto leggendo su DataAttributes per descrivere ulteriormente in C # cosa voglio che faccia il database; e la mia domanda è: quale penalità dovrò mangiare avendo queste nvarchar(max)stringhe nella mia tabella (vedi esempio sotto)?

Ci sono diverse colonne in questa particolare tabella; in C # sono definiti come tali:

    [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; }

Mi aspetto di eseguire una query e / o ordinare in base a Nome, Origine, Generato e Scritto. Mi aspetto che Nome e Sorgente abbiano una lunghezza di 0-50 caratteri, a volte fino a 150. Mi aspetto che questa tabella inizi abbastanza piccola (<100k righe), ma cresca in modo significativo nel tempo (> 1m righe). Ovviamente il messaggio potrebbe essere piccolo o grande e probabilmente non verrà interrogato.

Quello che voglio sapere, c'è un hit di performance per le mie colonne Nome e Sorgente che vengono definite come nvarchar(max)quando non mi aspetto che siano più grandi di 150 caratteri?


5
Sembra che tu debba applicare uno [MaxLength]o più [StringLength]attributi. Alcuni possibili ulteriori fattori negativi di colonne troppo larghe sono menzionati nella risposta di @ PaulWhite qui
Martin Smith,

3
, l'utilizzo varchar(max)dappertutto danneggia la tua performance - non farlo! Usa i tipi di dati appropriati : usa varchar(max) SOLO se hai davvero bisogno di più di 8000 caratteri! (Non ho mai visto il nome o l'e-mail di una persona così a lungo!) - Vedi qual è lo scopo di usare VARCHAR (n) Anymore? per maggiori informazioni
marc_s

@marc_s Ottimo collegamento. So che fa male alle prestazioni. Quando definisco le mie tabelle con SQL uso varchar (n). La mia domanda riguardava più di quanto danneggi le prestazioni (anche se realizzo come pubblicato che non era esplicitamente chiaro).
Nate,

Risposte:


24

Gli elementi di dati nvarchar (max) più grandi (oltre 8000 byte circa) si riverseranno nella memoria di testo e richiederanno I / O aggiuntivi. Gli articoli più piccoli verranno archiviati in fila. Esistono opzioni che controllano questo comportamento: vedi questo articolo MSDN per maggiori dettagli.

Se memorizzato nella riga, non vi è un sovraccarico di prestazioni I / O significativo; potrebbe esserci un sovraccarico di CPU aggiuntivo sull'elaborazione del tipo di dati, ma è probabile che questo sia minore.

Tuttavia, lasciare le colonne nvarchar (max) attorno al database dove non sono necessarie è una forma piuttosto scadente. Ha un certo sovraccarico di prestazioni e spesso le dimensioni dei dati sono abbastanza utili per comprendere una tabella di dati - ad esempio, una colonna varchar larga 50 o 100 caratteri potrebbe essere una descrizione o un campo di testo libero in cui uno che è (diciamo) 10- 20 caratteri probabilmente è un codice. Sareste sorpresi di quanto significato si debba spesso dedurre da un database attraverso ipotesi come questa.

Lavorare nel data warehousing, spesso non su sistemi legacy scarsamente supportati o documentati, avere uno schema di database facile da capire è piuttosto prezioso. Se pensi al database come all'eredità dell'applicazione, cerca di essere gentile con le persone che lo erediteranno da te.


18

Sebbene questo non risponda alla tua domanda specifica, potrebbe precluderti la necessità di porre la domanda in primo luogo: è possibile impostare una lunghezza sulle variabili di stringa nella classe del modello C #, che farà sì che Entity Framework generi SQL che utilizza un tipo nvarchar di lunghezza fissa (ad esempio nvarchar(50)), anziché nvarchar(max).

Ad esempio, anziché:

public string Name { get; set; }

Puoi usare:

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

Puoi anche forzare il tipo in modo che sia varcharinvece nvarchar, se lo desideri, come segue:

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

Fonte: https://stackoverflow.com/questions/7341783/entity-framework-data-annotations-set-stringlength-varchar/7341920


2
Ci è voluto trovare questa risposta per farmi capire che EF Core supporta contemporaneamente l'impostazione del tipo e della lunghezza ( varchar(50)), ma EF 6 richiede cosa c'è in questa risposta.
Sinjai,

9

Indicizzare la più grande preoccupazione. Da BOL:

Colonne che sono dei tipi di dati LOB (large object) ntext, text, varchar(max), nvarchar(max), varbinary(max), xml, o imagenon possono essere specificate come colonne chiave per un indice.

Se non riesci a indicizzare correttamente, avrai query lente. E dal punto di vista dell'integrità dei dati, avere nvarchar(max)consentirà di inserire più dati errati in un campo rispetto a quando si specifica il limite.


9

Sì, il comportamento EF predefinito nel mapping stringa nvarchar(max)non è buono. In EF 6 puoi aggiungere la tua convenzione personalizzata per sovrascrivere questo comportamento con la tua mappatura predefinita preferita.

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

    base.OnModelCreating(modelBuilder);
}

Sostituendo OnModelCreatingcome sopra cambierà il mapping predefinito per tutte le stringhe in varchar(200).


1
Questo non funziona in EF Core 1.0
Shittu Joseph Olugbenga,

the default EF behavior in mapping string to nvarchar(max) is not goodquesta sembra essere la tua opinione generalizzata. puoi spiegare perché questo non va bene? Oppure, pensi, EF non è un framework per applicazioni aziendali in cui devi lavorare con più lingue? Perché questo è il tipo di colonna desiderato per la gestione di più lingue nel database.
Matthias Burger,

1
@MatthiasBurger nvarchar (max) è orribile per le prestazioni, soprattutto in un ambiente replicato. Non è un'opinione generalizzata, è un fatto ben noto.
user2966445,

@utente2966445 scusa, penso che ci sia stato un malinteso :) certo, maxè orribile. Ma se vuoi gestire più lingue (e i loro diversi set di caratteri) devi usare nvarcharmi sbaglio?
Matthias Burger

@MatthiasBurger È corretto, usa nvarchar per diversi set di caratteri, ma l'intero post riguarda le prestazioni e la lunghezza dei campi, non l'uso di nvarchar vs. varchar.
user2966445
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.