Regole di confronto e distinzione tra maiuscole e minuscole

L'elaborazione del testo nei database può essere complessa e richiede più attenzione dell'utente rispetto a quella sospetta. Per un aspetto, i database variano notevolmente nella modalità di gestione del testo; Ad esempio, mentre alcuni database fanno distinzione tra maiuscole e minuscole per impostazione predefinita (ad esempio Sqlite, PostgreSQL), altri non fanno distinzione tra maiuscole e minuscole (SQL Server, MySQL). Inoltre, a causa dell'utilizzo degli indici, la distinzione tra maiuscole e minuscole e aspetti simili può avere un impatto di vasta portata sulle prestazioni delle query: anche se potrebbe essere tentata l'uso di un confronto senza distinzione tra maiuscole e minuscole in un database con distinzione tra maiuscole e minuscole, ciò potrebbe impedire all'applicazione di usare string.ToLower indici. Questa pagina illustra in dettaglio come configurare la distinzione tra maiuscole e minuscole o, più in generale, le regole di confronto e come eseguire questa operazione in modo efficiente senza compromettere le prestazioni delle query.

Introduzione alle regole di confronto

Un concetto fondamentale nell'elaborazione del testo è costituito dalle regole di confronto, ovvero un set di regole che determinano il modo in cui i valori di testo vengono ordinati e confrontati per l'uguaglianza. Ad esempio, mentre le regole di confronto senza distinzione tra maiuscole e minuscole ignorano le differenze tra lettere maiuscole e minuscole ai fini del confronto di uguaglianza, le regole di confronto con distinzione tra maiuscole e minuscole non vengono ignorate. Tuttavia, poiché la distinzione tra maiuscole e minuscole è sensibile alle impostazioni cultura (ad esempio i e rappresentano lettere diverse in turco), esistono più regole di confronto senza distinzione tra maiuscole e I minuscole, ognuna con un proprio set di regole. L'ambito delle regole di confronto si estende anche oltre la distinzione tra maiuscole e minuscole, ad altri aspetti dei dati di tipo carattere; in tedesco, ad esempio, è talvolta (ma non sempre) desiderabile trattare ä e ae come identico. Infine, le regole di confronto definiscono anche come vengono ordinati i valori di testo: mentre i punti ä tedeschi dopo a, svedese lo posiziona alla fine dell'alfabeto.

Tutte le operazioni di testo in un database usano regole di confronto, in modo esplicito o implicito, per determinare il modo in cui l'operazione confronta e ordina le stringhe. L'elenco effettivo delle regole di confronto disponibili e dei relativi schemi di denominazione è specifico del database; consultare la sezione seguente per i collegamenti alle pagine della documentazione pertinenti di vari database. Fortunatamente, i database consentono in genere di definire regole di confronto predefinite a livello di database o colonna e di specificare in modo esplicito le regole di confronto da usare per operazioni specifiche in una query.

Regole di confronto database

Nella maggior parte dei sistemi di database, le regole di confronto predefinite sono definite a livello di database; a meno che non venga sottoposto a override, tali regole di confronto si applicano in modo implicito a tutte le operazioni di testo che si verificano all'interno del database. Le regole di confronto del database vengono in genere impostate in fase di creazione del database (tramite l'istruzione CREATE DATABASE DDL) e, se non specificato, il valore predefinito è un valore a livello di server determinato in fase di installazione. Ad esempio, le regole di confronto a livello di server predefinite in SQL Server per le impostazioni locali del computer "Inglese (Stati Uniti)" sono SQL_Latin1_General_CP1_CI_AS, ovvero regole di confronto senza distinzione tra maiuscole e minuscole e con distinzione tra caratteri accentati. Anche se i sistemi di database in genere consentono di modificare le regole di confronto di un database esistente, questa operazione può causare complicazioni; è consigliabile selezionare regole di confronto prima della creazione del database.

Quando si usano le migrazioni di EF Core per gestire lo schema del database, nel metodo del OnModelCreating modello viene configurato un database di SQL Server per usare regole di confronto con distinzione tra maiuscole e minuscole:

modelBuilder.UseCollation("SQL_Latin1_General_CP1_CS_AS");

Regole di confronto a livello di colonna

Le regole di confronto possono essere definite anche nelle colonne di testo, ignorando l'impostazione predefinita del database. Ciò può essere utile se alcune colonne devono essere senza distinzione tra maiuscole e minuscole, mentre il resto del database deve fare distinzione tra maiuscole e minuscole.

Quando si usano le migrazioni di EF Core per gestire lo schema del database, di seguito viene configurata la colonna per la Name proprietà senza distinzione tra maiuscole e minuscole in un database che altrimenti è configurato per la distinzione tra maiuscole e minuscole:

modelBuilder.Entity<Customer>().Property(c => c.Name)
    .UseCollation("SQL_Latin1_General_CP1_CI_AS");

Regole di confronto esplicite in una query

In alcuni casi, è necessario eseguire query sulla stessa colonna usando regole di confronto diverse da query diverse. Ad esempio, potrebbe essere necessario eseguire un confronto con distinzione tra maiuscole e minuscole in una colonna, mentre un altro potrebbe dover eseguire un confronto senza distinzione tra maiuscole e minuscole nella stessa colonna. A tale scopo, è possibile specificare in modo esplicito regole di confronto all'interno della query stessa:

var customers = context.Customers
    .Where(c => EF.Functions.Collate(c.Name, "SQL_Latin1_General_CP1_CS_AS") == "John")
    .ToList();

Viene generata una COLLATE clausola nella query SQL, che applica regole di confronto con distinzione tra maiuscole e minuscole indipendentemente dalle regole di confronto definite a livello di colonna o di database:

SELECT [c].[Id], [c].[Name]
FROM [Customers] AS [c]
WHERE [c].[Name] COLLATE SQL_Latin1_General_CP1_CS_AS = N'John'

Regole di confronto e indici espliciti

Gli indici sono uno dei fattori più importanti per le prestazioni del database: una query eseguita in modo efficiente con un indice può interrompersi senza tale indice. Gli indici ereditano in modo implicito le regole di confronto della colonna; Ciò significa che tutte le query nella colonna sono automaticamente idonee all'uso degli indici definiti in tale colonna, a condizione che la query non specifichi regole di confronto diverse. Se si specificano regole di confronto esplicite in una query, in genere si impedisce che la query usi un indice definito in tale colonna, poiché le regole di confronto non corrispondono più; è quindi consigliabile prestare attenzione quando si usa questa funzionalità. È sempre preferibile definire le regole di confronto a livello di colonna (o database), consentendo a tutte le query di usare in modo implicito tali regole di confronto e trarre vantaggio da qualsiasi indice.

Si noti che alcuni database consentono di definire le regole di confronto durante la creazione di un indice, ad esempio PostgreSQL, Sqlite. In questo modo è possibile definire più indici nella stessa colonna, accelerando le operazioni con regole di confronto diverse, ad esempio confronti con distinzione tra maiuscole e minuscole e senza distinzione tra maiuscole e minuscole. Per altri dettagli, vedere la documentazione del provider di database.

Avviso

Esaminare sempre i piani di query delle query e assicurarsi che gli indici appropriati vengano usati nelle query critiche per le prestazioni eseguite su grandi quantità di dati. L'override della distinzione tra maiuscole e minuscole in una query tramite EF.Functions.Collate (o chiamando string.ToLower) può avere un impatto molto significativo sulle prestazioni dell'applicazione.

Traduzione di operazioni di stringa .NET predefinite

In .NET l'uguaglianza di stringhe fa distinzione tra maiuscole e minuscole per impostazione predefinita: s1 == s2 esegue un confronto ordinale che richiede che le stringhe siano identiche. Poiché le regole di confronto predefinite dei database variano e, poiché è consigliabile che l'uguaglianza semplice usi gli indici, EF Core non tenta di convertire la semplice uguaglianza in un'operazione con distinzione tra maiuscole e minuscole: l'uguaglianza C# viene convertita direttamente in uguaglianza SQL, che può essere o meno distinzione tra maiuscole e minuscole, a seconda del database specifico in uso e della relativa configurazione delle regole di confronto.

.NET fornisce inoltre overload per string.Equals accettare un'enumerazione StringComparison , che consente di specificare la distinzione tra maiuscole e minuscole e impostazioni cultura per il confronto. Per impostazione predefinita, EF Core non esegue la conversione di questi overload in SQL e il tentativo di usarli genererà un'eccezione. Per un aspetto, EF Core non conosce le regole di confronto con distinzione tra maiuscole e minuscole o senza distinzione tra maiuscole e minuscole. Soprattutto, l'applicazione di regole di confronto impedirebbe nella maggior parte dei casi l'utilizzo degli indici, con un impatto significativo sulle prestazioni per un costrutto .NET di base e di uso comune. Per forzare una query a usare un confronto con distinzione tra maiuscole e minuscole o senza distinzione tra maiuscole e minuscole, specificare le regole di confronto in modo esplicito tramite EF.Functions.Collate come descritto in precedenza.

Risorse aggiuntive

Informazioni specifiche del database

Altre risorse

  • Sessione di standup della community di dati .NET, introduzione di regole di confronto ed esplorazione di aspetti relativi alle prestazioni e all'indicizzazione.