Sortierungen und Unterscheidung nach Groß-/Kleinschreibung

Die Textverarbeitung in Datenbanken kann kompliziert sein und erfordert mehr Aufmerksamkeit der Benutzer*innen, als eventuell vermutet. Zum einen unterscheiden sich Datenbanken erheblich beim Verarbeiten von Text. Während bei einigen Datenbanken die Groß-/Kleinschreibung standardmäßig beachtet wird – z. B. bei Sqlite und PostgreSQL –, wird bei anderen Datenbanken die Groß-/Kleinschreibung nicht beachtet, z. B. bei SQL Server, MySQL. Darüber hinaus können das Beachten von Groß-/Kleinschreibung und ähnliche Aspekte aufgrund der Indexverwendung weitreichende Auswirkungen auf die Abfrageleistung haben. Zwar kann es verlockend sein, mit string.ToLower einen Vergleich, bei dem die Groß-/Kleinschreibung nicht beachtet wird, in einer Datenbank mit Groß-/Kleinschreibung zu erzwingen, doch dies kann dazu führen, dass Ihre Anwendung keine Indizes verwendet. Auf dieser Seite wird erläutert, wie Sie das Beachten der Groß-/Kleinschreibung bzw. allgemein Sortierungen konfigurieren, und dies auf effiziente Weise tun, ohne die Abfrageleistung zu beeinträchtigen.

Einführung in Sortierungen

Ein grundlegendes Konzept bei der Textverarbeitung ist die Sortierung, bei der es sich um Regeln zum Bestimmen handelt, wie Textwerte sortiert und auf Gleichheit überprüft werden. Während beispielsweise bei einer Sortierung, bei der Groß- und Kleinschreibung nicht beachtet wird, Unterschiede zwischen Groß- und Kleinbuchstaben für die Gleichheitsvergleiche ignoriert werden, ist dies bei einer Sortierung, bei der Groß- und Kleinschreibung beachtet wird, nicht der Fall. Da die Beachtung von Groß-/Kleinschreibung jedoch kulturabhängig ist – z. B. stellen im Türkischen i und I unterschiedliche Buchstaben dar –, gibt es mehrere Sortierungen, bei denen die Groß-/Kleinschreibung nicht beachtet wird. Diese verfügen jeweils über eigene Regeln. Der Umfang von Sortierungen geht auch über die Beachtung von Groß-/Kleinschreibung hinaus und umfasst andere Aspekte von Zeichendaten. Zum Beispiel ist es im Deutschen manchmal nützlich, wenn auch nicht immer, ä und ae als identisch zu behandeln. Schließlich definieren Sortierungen auch, wie Textwerte sortiert werden: Während im Deutschen ä nach a gelistet wird, steht dies im Schwedischen am Ende des Alphabets.

Alle Textvorgänge in einer Datenbank verwenden eine Sortierung zum Bestimmen, wie der Vorgang Zeichenfolgen vergleicht und sortiert, egal ob explizit oder implizit. Die tatsächliche Liste der verfügbaren Sortierungen und ihrer Benennungsschemata ist datenbankspezifisch. Links zu den entsprechenden Dokumentationsseiten der verschiedenen Datenbanken finden Sie im Bereich unten. Glücklicherweise erlauben Datenbanken in der Regel, dass eine Standardsortierung auf Datenbank- oder Spaltenebene definiert wird, und dass explizit angegeben werden kann, welche Sortierung für bestimmte Vorgänge in einer Abfrage verwendet werden soll.

Datenbanksortierung

In den meisten Datenbanksystemen wird eine Standardsortierung auf Datenbankebene definiert. Sofern diese nicht außer Kraft gesetzt wird, gilt diese Sortierung implizit für alle Textvorgänge in dieser Datenbank. Die Datenbanksortierung wird in der Regel zur Erstellungszeit der Datenbank über die DDL-Anweisung CREATE DATABASE festgelegt. Wenn diese nicht angegeben ist, wird standardmäßig ein bestimmter Wert auf Serverebene festgelegt, der zur Einrichtungszeit bestimmt wird. Die Standardsortierung auf Serverebene in SQL Server für das Gebietsschema "Englisch (USA)" lautet beispielsweise SQL_Latin1_General_CP1_CI_AS. Dabei handelt es sich um eine Sortierung ohne Beachten von Groß-/Kleinschreibung mit Unterscheidung nach Akzent. Obwohl Datenbanksysteme in der Regel ein Ändern der Sortierung einer vorhandenen Datenbank zulassen, kann dies zu Komplikationen führen. Es wird empfohlen, vor der Datenbankerstellung eine Sortierung auszuwählen.

Beim Verwenden von EF Core-Migrationen zum Verwalten ihres Datenbankschemas konfiguriert Folgendes in Ihrer Methode OnModelCreating Ihres Modells eine SQL Server-Datenbank zum Nutzen einer Sortierung, bei der Groß-/Kleinschreibung beachtet wird:

modelBuilder.UseCollation("SQL_Latin1_General_CP1_CS_AS");

Spaltensortierung

Sortierungen können auch für Textspalten definiert werden, wobei der Datenbankstandard außer Kraft gesetzt wird. Dies kann hilfreich sein, wenn bei bestimmten Spalten die Groß-/Kleinschreibung nicht beachtet werden muss, während sie bei der restlichen Datenbank beachtet werden muss.

Wenn Sie EF Core-Migrationen zum Verwalten Ihres Datenbankschemas verwenden, konfiguriert Folgendes die Spalte für die Eigenschaft Name, damit die Groß-/Kleinschreibung in einer Datenbank nicht beachtet werden muss, die andernfalls so konfiguriert ist, dass die Groß-/Kleinschreibung beachtet wird:

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

Explizite Sortierung in einer Abfrage

In einigen Fällen muss dieselbe Spalte mit unterschiedlichen Sortierungen von verschiedenen Abfragen abgefragt werden. Zum Beispiel muss mit einer Abfrage ein Vergleich in einer Spalte durchgeführt werden, bei dem Groß-/Kleinschreibung beachtet werden muss, während mit einer anderen möglicherweise einen Vergleich in derselben Spalte stattfindet, bei der Groß-/Kleinschreibung nicht beachtet werden muss. Dies kann erreicht werden, indem eine Sortierung innerhalb der Abfrage selbst explizit angegeben wird:

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

Dadurch wird eine COLLATE-Klausel in der SQL-Abfrage generiert, die unabhängig von der Sortierung, die auf Spalten- oder Datenbankebene definiert ist, eine Sortierung mit Beachtung der Groß-/Kleinschreibung anwendet:

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

Explizite Sortierungen und Indizes

Indizes sind einer der wichtigsten Faktoren bei der Datenbankleistung. Eine Abfrage, die effizient mit einem Index ausgeführt wird, kann ohne diesen anhalten. Indizes erben implizit die Sortierung ihrer Spalte. Dies bedeutet, dass alle Abfragen für die Spalte automatisch berechtigt sind, in dieser Spalte definierte Indizes zu verwenden. Voraussetzung dafür ist, dass die Abfrage keine andere Sortierung angibt. Das Angeben einer expliziten Sortierung in einer Abfrage verhindert in der Regel, dass diese Abfrage einen in dieser Spalte definierten Index verwenden kann, da die Sortierungen nicht mehr übereinstimmen würden. Es wird daher empfohlen, beim Verwenden dieses Features Vorsicht walten zu lassen. Die Sortierung sollte immer auf Spalten- oder Datenbankebene definiert werden, damit alle Abfragen diese Sortierung implizit verwenden und sie von jedem Index profitieren können.

Beachten Sie, dass einige Datenbanken das Definieren einer Sortierung beim Erstellen eines Indexes ermöglichen, beispielsweise PostgreSQL und Sqlite. Auf diese Weise können mehrere Indizes für dieselbe Spalte definiert werden, wodurch Vorgänge mit unterschiedlichen Sortierungen beschleunigt werden, z. B. bei Vergleichen, bei denen Groß- und Kleinschreibung beachtet und nicht beachtet werden muss. Nähere Informationen dazu finden Sie in der Dokumentation Ihres Datenbankanbieters.

Warnung

Überprüfen Sie immer die Abfragepläne, und stellen Sie sicher, dass die richtigen Indizes in leistungskritischen Abfragen verwendet werden, die mit denen große Datenmengen verarbeitet werden. Das Außerkraftsetzen der Beachtung von Groß-/Kleinschreibung in einer Abfrage mithilfe von EF.Functions.Collate oder durch Aufrufen von string.ToLower kann erhebliche Auswirkungen auf die Leistung Ihrer Anwendung haben.

Übersetzung integrierter .NET-Zeichenfolgenvorgänge

In .NET wird bei der Zeichenfolgengleichstellung standardmäßig die Groß-/Kleinschreibung beachtet: s1 == s2 führt einen Ordinalvergleich aus, bei dem die Zeichenfolgen identisch sein müssen. Da die Standardsortierung von Datenbanken unterschiedlich ist und es wünschenswert ist, Indizes für einfache Gleichheit zu verwenden, wird mit EF Core nicht versucht, einfache Gleichheit in einen Datenbankvorgang zu übersetzen, bei dem Groß-/Kleinschreibung beachtet werden muss. C#-Gleichheit wird direkt in SQL-Gleichheit übersetzt, die je nach verwendeter Datenbank und deren Sortierungskonfiguration die Groß-/Kleinschreibung beachtet.

Darüber hinaus stellt .NET Überladungen bereit, bei denen string.Equals eine StringComparison-Enumeration akzeptiert, wodurch die Beachtung der Groß-/Kleinschreibung und eine Kultur für den Vergleich angegeben werden können. Standardmäßig werden diese Überladungen mit EF Core nicht in SQL übersetzt, und der Versuch, sie zu verwenden, führt zu einer Ausnahme. EF Core weiß zum einen nicht, welche Sortierung beachtet werden sollte, bei der eventuell die Groß-/Kleinschreibung beachtet wird. Viel wichtiger ist jedoch, dass das Anwenden einer Sortierung in den meisten Fällen die Indexverwendung verhindern und die Leistung für ein sehr einfaches und häufig verwendete .NET-Konstrukt erheblich beeinträchtigen würde. Wenn sie erzwingen möchten, dass bei einer Abfrage ein Vergleich verwendet wird, bei dem Groß- und Kleinschreibung entweder beachtet wird oder nicht, geben Sie eine Sortierung explizit über EF.Functions.Collate an, wie oben beschrieben.

Zusätzliche Ressourcen

Datenbankspezifische Informationen

Weitere Ressourcen