效能模型化
在許多情況下,模型化的方式可能會對應用程式的效能產生深遠的影響:雖然正常化且「正確」的模型通常是一個很好的起點,但在真實世界中,有些務實的妥協對於達到良好效能可能還有很長的路要走。 由於一旦應用程式在生產環境中執行,就很難變更您的模型,因此在建立初始模型時,值得記住效能。
反正規化和快取
反正規化 是將備援數據新增至架構的做法,通常是為了在查詢時消除聯結。 例如,對於具有部落格和文章的模型,其中每個文章都有評等,您可能需要經常顯示部落格的平均評等。 此方法的簡單方法會依部落格將文章分組,並計算查詢的平均值;但這需要兩個數據表之間的昂貴聯結。 反正規化會將所有文章的計算平均值新增至 Blog 上的新數據行,以便立即存取,而不需要聯結或計算。
上述可檢視為快取形式 - 文章的匯總資訊會快取在其部落格上;就像任何快取一樣,問題在於如何讓快取值與快取的數據保持最新狀態。 在許多情況下,快取的數據可以延遲一點:例如,在上述範例中,部落格的平均評等通常不完全處於任何指定時間點的最新資訊是合理的。 如果是這種情況,您可以立即重新計算它;否則,必須設定更詳細的系統,讓快取的值保持在最新狀態。
下列詳細說明 EF Core 中反正規化和快取的一些技術,並指向檔中的相關章節。
儲存的計算數據行
如果要快取的數據是相同數據表中其他數據行的乘積,則 預存計算數據行 可以是完美的解決方案。 例如,可能有 Customer
FirstName
和 LastName
數據行,但我們可能需要依客戶 的完整名稱進行搜尋。 資料庫會自動維護預存計算數據行,每當數據列變更時就會重新計算它,您甚至可以定義索引來加速查詢。
輸入變更時更新快取數據行
如果您的快取資料行需要參考資料表數據列外部的輸入,您就無法使用計算數據行。 不過,每當數據行的輸入變更時,仍然可以重新計算數據行;例如,您可以在每次變更、新增或移除文章時,重新計算平均部落格的評等。 請務必識別需要重新計算時的確切條件,否則快取的值將會不同步。
若要這樣做,其中一個方法是透過一般 EF Core API 自行執行更新。 SaveChanges
事件或攔截器可用來自動檢查是否有任何文章正在更新,以及以這種方式執行重新計算。 請注意,這通常需要額外的資料庫往返,因為必須傳送額外的命令。
如需更多區分效能的應用程式,可以定義資料庫觸發程式,以自動執行資料庫中的重新計算。 這樣可節省額外的資料庫往返,自動在與主要更新相同的交易內發生,而且可以更容易設定。 EF 不會提供任何特定的 API 來建立或維護觸發程式,但建立空白移轉並透過原始 SQL 新增觸發程式定義是完全正確的。
具體化/索引檢視
具體化 (或索引) 檢視類似於一般檢視,不同之處在於其數據會儲存在磁碟上(「具體化」),而不是每次查詢檢視時計算。 這類檢視在概念上類似於預存的計算數據行,因為它們會快取可能昂貴的計算結果:不過,它們會快取整個查詢的結果集,而不是單一數據行。 具體化檢視可以和任何一般數據表一樣進行查詢,而且由於查詢是在磁碟上快取的,因此這類查詢的執行非常快速且便宜,而不需要持續執行定義檢視的查詢成本高昂的計算。
具體化檢視的特定支援會因資料庫而異。 在某些資料庫中,必須手動重新整理具體化檢視,才能將其值與其基礎表同步處理。 這通常是透過定時器完成的,以防某些數據延隔時間是可接受的,或透過特定條件下的觸發程式或預存過程調用來完成。 另一方面,SQL Server 索引檢視會隨著基礎表的修改而自動更新;這可確保檢視一律會以較慢的更新為代價顯示最新的數據。 此外,SQL Server 索引檢視對支援的專案有各種限制:如需詳細資訊, 請參閱檔 。
EF 目前未提供任何特定 API 來建立或維護檢視、具體化/索引或其他;但建立空白移轉並透過原始 SQL 新增檢視定義是完全正確的。
繼承對應
建議您先閱讀 繼承 的專用頁面,再繼續進行本節。
EF Core 目前支援三種將繼承模型對應至關係資料庫的技術:
- 每個階層 的數據表 (TPH),其中類別的整個 .NET 階層會對應至單一資料庫數據表。
- 每一類型的 數據表 (TPT),其中 .NET 階層中的每個類型都會對應至資料庫中的不同數據表。
- 數據表個別具象類型 (TPC),其中 .NET 階層中的每個具體類型都會對應至資料庫中的不同數據表,其中每個數據表都包含對應類型之所有屬性的數據行。
繼承對應技術的選擇可能會對應用程式效能產生相當大的影響,建議您先仔細測量,再認可選擇。
直覺上,TPT 可能看起來像是「更清潔」的技術;每個 .NET 類型的個別數據表,讓資料庫架構看起來類似 .NET 類型階層。 此外,由於 TPH 必須代表單一數據表中的整個階層,因此數據列具有 所有數據 行,而不論實際保留在數據列中的類型為何,且不相關的數據行一律是空白且未使用的。 除了看似「不乾淨」的對應技術之外,許多人還認為,這些空白數據行在資料庫中佔用了大量空間,而且可能會損害效能。
提示
如果您的資料庫系統支援它 (e.g. SQL Server),請考慮針對很少填入的 TPH 資料行使用「疏鬆數據行」。
不過,量值顯示 TPT 在大部分情況下,效能觀點是劣質的對應技術:當 TPH 中的所有數據都來自單一數據表時,TPT 查詢必須聯結多個數據表,而聯結是關係資料庫中效能問題的主要來源之一。 資料庫通常也會妥善處理空的數據行,而 SQL Server 疏鬆數據行等功能可能會進一步降低此額外負荷。
TPC 具有與 TPH 類似的效能特性,但在選取所有類型的實體時會稍微慢一點,因為這牽涉到數個數據表。 不過,在查詢單一分葉類型的實體時,TPC 確實很出色- 查詢只會使用單一數據表,而且不需要篩選。
如需具體範例, 請參閱此基準檢驗 ,其會設定具有 7 種階層的簡單模型;每個類型會植入 5000 個數據列 - 總計 35000 個數據列 ,而基準檢驗只會從資料庫載入所有數據列:
方法 | 平均數 | 錯誤 | StdDev | Gen 0 | 第 1 代 | 已配置 |
---|---|---|---|---|---|---|
TPH | 149.0 毫秒 | 3.38 毫秒 | 9.80 毫秒 | 4000.0000 | 1000.0000 | 40 MB |
TPT | 312.9 毫秒 | 6.17 毫秒 | 10.81 毫秒 | 9000.0000 | 3000.0000 | 75 MB |
TPC | 158.2 毫秒 | 3.24 毫秒 | 8.88 毫秒 | 5000.0000 | 2000.0000 | 46 MB |
如所見,TPH 和 TPC 比此案例的 TPT 更有效率。 請注意,實際結果一律取決於所執行的特定查詢和階層中的數據表數目,因此其他查詢可能會顯示不同的效能差距:建議您使用此基準檢驗程式代碼作為測試其他查詢的範本。