排序與大小寫敏感性

資料庫中的文字處理可能相當複雜,且需要比想像中更多的使用者注意力。 首先,資料庫在處理文字的方式上差異很大;例如,有些資料庫預設是大小寫區分的(例如 Sqlite、PostgreSQL),但有些則是不區分大小寫的(SQL Server、MySQL)。 此外,由於使用索引,大小寫區分和類似因素可能對查詢效能產生深遠影響:在大小寫敏感的資料庫中使用 string.ToLower 強制進行不分大小寫的比較可能會很吸引人,但這樣可能會阻止你的應用程式利用索引。 本頁詳細說明如何配置大小寫敏感度,或更廣義地說,彙整,以及如何在不犧牲查詢效能的情況下有效率地進行。

排序規則導論

文本處理中的一個基本概念是 排序,這是一組規則,用以決定文本值的排序與比較以達到相等。 例如,不區分大小寫的排序規則會在等效比較中忽略大小寫字母的差異,而區分大小寫的排序規則則不會。 然而,由於大小寫區分是文化敏感的(例如 i 和 I 代表土耳其語中不同的字母),因此存在多種不區分大小寫的排序,每種都有自己的一套規則。 排序的範圍不僅限於大小寫敏感性,還涵蓋字元資料的其他方面,例如在德語中,有時(但不總是)會希望將 ä 和 ae 視為相同。 最後,排序規則也定義了文本值的排列方式:德文將ä放在a後,而瑞典文則將其置於字母表末尾。

資料庫中的所有文字操作都會使用排序——無論是顯式或隱式——來判斷操作如何比較並排序字串。 實際可用的彙整清單及其命名方式是資料庫特定的;請參閱 下方章節 ,以取得各資料庫相關文件頁面的連結。 幸運的是,資料庫通常允許在資料庫或欄位層級定義預設的排序,並明確指定查詢中特定操作應使用哪種排序。

資料庫定序

在大多數資料庫系統中,預設的排序會在資料庫層級定義;除非被覆寫,否則該排序隱含適用於該資料庫中發生的所有文字操作。 資料庫整合通常在建立資料庫時(透過 CREATE DATABASE DDL 陳述式)設定,若未指定,則預設為設定時決定的伺服器層級值。 例如,SQL Server 中「English (United States)」機器區域的預設伺服器層級排序為 SQL_Latin1_General_CP1_CI_AS,這是一種不區分大小寫且重音敏感的排序。 雖然資料庫系統通常允許修改現有資料庫的排序,但這可能會帶來複雜性;建議在建立資料庫前先選擇一個彙整。

使用 EF Core 遷移來管理資料庫結構時,可在模型的 OnModelCreating 方法中進行以下設定,以將 SQL Server 資料庫配置為區分大小寫的排序規則:

modelBuilder.UseCollation("SQL_Latin1_General_CP1_CS_AS");

欄位對照

排序規則也可以在文字欄位上定義,以取代資料庫的預設值。 如果某些欄位需要不區分大小寫,而資料庫其他部分則需要區分大小寫,這會很有用。

使用 EF Core 遷移管理資料庫結構時,以下步驟將 Name 該屬性欄位設定為不區分大小寫,而資料庫本身已設定為大小寫區分:

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

查詢中的明確排序規則

在某些情況下,同一欄位需要透過不同的排序規則進行不同的查詢。 例如,一個查詢可能需要對某欄位進行大小寫區分比較,而另一個查詢則可能需要對同一欄位進行大小寫不區分的比較。 這可以透過在查詢本身中明確指定一個排序來達成:

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

這會在 COLLATE SQL 查詢中產生一個子句,無論欄位或資料庫層定義的排序如何,都會套用大小寫區分的排序:

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

明確的排序與索引

索引是資料庫效能中最重要的因素之一,有索引的查詢能有效運行,而沒有索引可能會讓查詢停滯不前。 索引隱含地繼承其欄位的排序;這表示該欄位上的所有查詢都能自動使用該欄位定義的索引——前提是查詢沒有指定不同的排序。 在查詢中指定明確的排序通常會阻止該查詢使用該欄位定義的索引,因為整合結果將不再匹配;因此,使用此功能時建議謹慎。 通常最好在欄位(或資料庫)層級定義整合,讓所有查詢都能隱含使用該排序,並從任何索引中受益。

請注意,有些資料庫允許在建立索引時定義整合(例如 PostgreSQL、Sqlite)。 這使得同一欄可定義多個索引,加快不同排序(例如大小寫區分與不區分大小寫的比較)操作。 請參閱您的資料庫供應商文件以獲取更多細節。

警告

務必檢查查詢的計畫,並確保在執行大量資料的效能關鍵查詢中,使用正確的索引。 在查詢中覆寫大小寫敏感性,透過EF.Functions.Collate或呼叫string.ToLower,可能對應用程式的效能產生非常顯著的影響。

內建 .NET 字串操作的轉譯

在 .NET 中,字串相等預設為大小寫區分:s1 == s2 執行序數比較,要求字串必須完全相同。 由於資料庫的預設排序方式會有所不同,且希望簡單的等式使用索引,EF Core 並未嘗試將簡單的等式轉換為資料庫大小寫區分的操作:C# 等式會直接轉換成 SQL 等式,而 SQL 等式則可能不區分大小寫,取決於所使用的資料庫及其整合配置。

此外,.NET 提供接受string.Equals列舉的StringComparison多載功能,允許指定比較時的大小寫敏感度及文化特性。 設計上,EF Core 避免將這些超載轉換成 SQL,嘗試使用它們會觸發例外。 首先,EF Core 不知道應該使用哪種大小寫區分或不區分大小寫的排序。 更重要的是,套用彙整在大多數情況下會防止索引使用,對這個非常基礎且常用的 .NET 結構來說,效能會造成重大影響。 若要強制查詢使用大小寫區分或不區分大小寫的比較,請如EF.Functions.Collate明確指定一個排序規則。

其他資源

資料庫特定資訊

其他資源