效能簡介

資料庫效能是龐大且複雜的主題,橫跨整個元件堆疊:資料庫、網路、資料庫驅動程式和 EF Core 等資料存取層。 雖然 EF Core 等高階層和 O/RM 可大幅簡化應用程式開發並改善可維護性,有時卻可能不夠透明,隱藏重大效能內部詳細資料,例如正在執行的 SQL。 本節會嘗試概述如何使用 EF Core 達到良好效能,以及如何避免有礙應用程式效能的常見錯誤。

識別瓶頸和量值、量值、量值

就像對待效能一樣,千萬不要在還沒有資料指出問題的情況下,急於開始最佳化;Donald Knuth 曾經說過:「過早最佳化是萬惡的根源」。 效能診斷一節會討論各種方式,以了解秏費應用程式時間的資料庫邏輯層面,以及如何找出特定的問題區域。 找到速度緩慢的查詢之後,就可以考慮解決方案:資料庫是否遺漏索引? 應該嘗試其他查詢模式嗎?

請一律自行對程式碼和可能的替代方案進行基準測試,<效能診斷>一節有 BenchmarkDotNet 的範例基準測試,您可以此為基準測試的範本。 請勿將一般的公開基準原樣照搬到特定的使用案例,資料表中的各種因素,例如資料庫延遲、查詢複雜度和實際資料量,都可能會對最佳解決方案的勝負產生重大影響。 例如,許多公開基準要在理想的網路狀況下才會實現,其資料庫延遲幾乎為零,而且資料庫端幾乎不需要處理任何查詢 (或磁碟 I/O)。 雖然這些基準在比較不同資料存取層的執行階段額外負荷時十分有用,但其所揭露的差異在實際應用中通常證明是可忽略的,當資料庫執行實際工作時,資料庫延遲是很重要的效能因素。

資料存取效能的各個層面

整體資料存取效能可細分為下列幾大類別:

  • 單純資料庫效能。 使用關聯式資料庫時,EF 會將應用程式的 LINQ 查詢轉譯為資料庫執行的 SQL 陳述式;而這些 SQL 陳述式本身執行時或多或少還算有效率。 正確的索引在正確的位置,會讓 SQL 效能天差地別,或者重寫 LINQ 查詢可能會讓 EF 產生更好的 SQL 查詢。
  • 網路資料傳輸。 和所有網路系統一樣,請務必限制網路上來回傳輸的資料量。 這包括確保只傳送與載入實際需要的資料,但也要避免在載入相關實體時所謂的「笛卡兒暴增」效果。
  • 網路往返。 除了受來回資料量影響外,網路往返在資料庫中執行查詢所花費的時間,還可能因為在應用程式與資料庫之間來回移動封包的時間而縮短。 往返額外負荷高度取決於您的環境,資料庫伺服器距離愈遠,延遲就愈高,且每次往返也愈昂貴。 雲端問世後,應用程式距離資料庫愈來愈遠,而執行過多往返體驗的「聊天」應用程式則降低了效能。 因此,請務必確切掌握應用程式連絡資料庫的時間、執行往返的次數,以及此次數可否降至最低。
  • EF 執行階段額外負荷。 最後,EF 本身也會增加資料庫作業的執行階段額外負荷:EF 需要將查詢從 LINQ 編譯成 SQL (雖然這通常應該只執行一次)、變更追蹤會增加一些額外負荷 (但可以停用) 等等。在實務中,真實世界應用程式的 EF 額外負荷大多可能微不足道,因為資料庫的查詢執行時間和網路延遲就佔據大部分的總時間,但請務必了解您的選擇是什麼,以及如何避免一些錯誤。

了解幕後發生了什麼事

EF 可讓開發人員透過產生 SQL、具體化結果與執行其他工作,以專注於商務邏輯。 就像任何層或抽象概念一樣,其一般也會隱藏幕後的真實情況,例如正在執行的實際 SQL 查詢。 對每個應用程式而言,效能不一定很重要,但對開發人員了解 EF 可為應用程式有何幫助卻非常重要:檢查傳出的 SQL 查詢、追蹤往返以確保 N+1 個問題不會發生等等。

資料庫外部的快取

最後,與資料庫互動最有效率的方式,就是完全不與其互動。 換句話說,如果資料庫存取在您的應用程式中顯示為效能瓶頸,就值得快取資料庫外部的特定結果,以將要求降到最低。 雖然快取會增加複雜度,卻是任何可縮放應用程式特別重要的一環:雖然透過新增額外的伺服器可輕鬆縮放應用程式層,以處理增加的負載,但縮放資料庫層通常更為複雜。