[Data Access] ORM 原理 (11): 效能議題
這絕對是 ORM 的使用者,開發人員與 DBAs 共同想要問的議題,到底我使用了 ORM 和使用傳統的 ADO.NET 下 SQL 指令的方式會差多少? 這個問題不但會發生在 Entity Framework 上,也會發生在 NHibernate 等 ORM Framework 內,連同我自己在這個系列文中開發的 ORM 機制也會受到影響。
我們在前面的 ORM 1-9 系列文中看到了整個開發 ORM 所需要的技術和方法,然後也實作出了一個完整的 ORM Framework (再簡單不過的版本),我們在這個 ORM Framework 中用了下列技術:
- Reflection,這是最重要的技術,沒有它,就無法動態的對應 Property 和 Field。
- Attribute,少了它就沒辦法宣告自訂對應 (在 ORM (9) 有程式化的對應)。
- Type Converter,沒有它的話就無法轉換資料,尤其是資料中有列舉值時。
- SQL Generation,自動產生 SQL 指令,讓開發人員不再需要撰寫 SQL。
- ADO.NET,最核心的物件,而且只使用 Connection, Command 與 DataReader。
- Provider Pattern,利用它來切換不同的資料提供者。
- LINQ Expression,在 ORM (9) 時實作 Coded Map 之用。
而在使用這些技術時,有哪些情況會影響到效能?
1. 動態產生的 SQL
當 ORM Framework 接到物件存取資料庫的要求時,通常會有一個機制來產生 SQL 指令,再交由 ADO.NET 存取資料,但是你知道 ORM Framework 產生的 SQL 指令的樣貌嗎?因為 SQL 指令的下法會影響 DBMS 存取資料的效能,而 SQL 指令若是由 ORM Framework 產生的話,表示開發人員沒辦法自己去修改 SQL 來做這件事。最常見的解決方法,就是自己寫 SQL,而多數的 ORM Framework 都還是會提供一個讓開發人員直接執行 SQL 的方法,而回傳的可以是 DataReader 或是由開發人員指定的 DTO (POCO) 物件。
ORM 被 DBA 攻擊的其中一個點,就是 DBA 無法介入寫 SQL 這件事,對於一些具有規模的系統來說,SQL 都是 DBA 在寫的,但卻無法相容於 ORM Framework 或是開發人員所寫的 POCO 物件,這時就會有問題,而且多數的大系統,通常不會允許由開發人員自己寫 SQL 存取表格,而是用檢視表或是預存程序或函數等資料庫物件來存取,所以主流的 ORM Framework 都有提供可存取資料庫物件的功能,這樣 DBA 就能將 SQL 指令的效能影響降低 (或是把效能責任推給開發人員…)。但對於小型專案而言,SQL 指令要由開發人員來處理,因此若要用 ORM 來替代寫 SQL 的工作,就等於要承受 ORM 產生的 SQL 的效能問題,但還是可以透過自己寫 SQL 來處理,所以最後的問題還是會落在 SQL 的寫法好不好。
Entity Framework 和 NHibernate 等主流 ORM 都會花不少的心思來調校自動產生的 SQL,也會提供輸出它所產生的 SQL 的方式,例如 EF 有 ObjectQuery.ToTraceString(), NH 也有提供方法捕捉。雖然我自己寫的 ORM Framework 沒有提供這功能,但仍可以改寫它來提供這樣的能力。而 DBA 或開發人員就可以利用得到的 SQL 來做調校工作,例如調整索引或是更新統計資料等工作,來調整 SQL 執行的效能,或是自己寫 SQL 來做。
2. 撈取資料時的方式
使用 ADO.NET 撈取資料的話,用 DataReader 一定是最快的,搭配上 Sequential Access 那幾乎等於無敵,除非開發人員要自己處理 SQL protocols (ex: SQL Server 的 TDS),否則以 ADO.NET 內建的資料存取方式來說,DataReader 己經是最快的作法了,若是轉成 DataTable 再讀入,會有兩段的 Type Casting 負擔,不符合 ORM Framework 的基本要求。
Sequential Access 的好處是會逐項依目前游標的位置來讀取,不必推算資料流的位置,所以速度很快,但因為它不會推算資料流,所以它也不能捲回前面的資料流位置,這點在使用上要特別注意。
3. 對應欄位與屬性時的處理
這點就是 ORM 最大的罩門了,要做到程式化的 Property <-> Field 對應,一定得依賴 Reflection,而 Reflection 最花時間的地方莫過於取得 Property Metadata 這一塊,所以如果可以事先快取 Property Metadata 的話,在讀取資料時就可以快近三四倍 (這是我自己實證的經驗)。
再來是 Type Casting 的問題,這個其實很難避免,數值型別的話還好有 Convert 物件可用,但若是自訂型別的話,就只能自己寫一個 Type Converter 來做,這時用泛型會比用 object 來得優,因為可以省下 box/unbox 的效能損耗。
4. 延遲載入
延遲載入 (Lazy Loading) 在前面的 ORM 文章有提到,在有關聯性的資料模型內,有時使用 ORM 產生物件時,不一定會用到關聯的資料,所以我們可以選擇要用時再載入,如此可以省下一次 SQL 的負載,而且就算是物件本身,也可以只載入像 ID/Name 這種必要資料,若需要更多資料時再進一步載入即可,但負面的問題就是它需要好幾個 SQL 才能完全載入必要的資料,但如果一次載入大資料和分多次載入小資料相比,我想後者的效能會好些。
5. 其他的考量
懂得整個資料存取與資料庫處理流程的開發人員,而且是在特定的 DBMS 之下時,可以針對該 DBMS 做更進一步的最佳化,例如像 SQL 查詢計畫快取 (Query Plan Caching),SQL 快取 (SQL Caching),物件快取 (Object Caching) 等,簡化 SQL 和 DBMS 的查詢負擔,並且加快整個 ORM Framework 的速度,另外像是語法的下法 (ex: LINQ to Entities 的查詢下法) 和關聯的使用技巧等都會間接影響到 ORM 的效能。
說了這麼多,我所要強調的是,ORM 是好用的資料存取方式,但它一定會有某種程度不可避免的效能損耗,我們可以做的事,就是將這些損耗降到最低,讓整體的資料存取速度加快,所以當看到了 ORM 的好處時,也不能忘了它也有缺點,而事先了解它的缺點並予以注意或改善,再來好好的享受它的優點,也不錯。
Reference:
http://msdn.microsoft.com/en-us/data/hh949853.aspx
===================================
[Data Access] ORM 原理 (11): 效能議題的更多相关文章
- DevExpress v18.1新版亮点——Data Access篇
用户界面套包DevExpress v18.1日前正式发布,本站将以连载的形式为大家介绍各版本新增内容.本文将介绍了DevExpress Data Access v18.1 的新功能,快来下载试用新版本 ...
- .NET Core Data Access
.NET Core was released a few months ago, and data access libraries for most databases, both relation ...
- Spring.NET的中间数据层(Middle Tier Data Access)——事务管理(Transaction management)
简介 Spring.NET为事务管理提供了一个持久化抽象(consistent abstraction ),其优点如下: 为不同事务API,例如ADO.NET,Enterprise Services, ...
- FunDA(0)- Functional Data Access accessible to all
大数据.多核CPU驱动了函数式编程模式的兴起.因为函数式编程更适合多线程.复杂.安全的大型软件编程.但是,对许多有应用软件开发经验的编程者来说,函数式编程模式是一种全新的.甚至抽象的概念,可能需要很长 ...
- Top 10 steps to optimize data access in SQL Server
2009年04月28日 Top 10 steps to optimize data access in SQL Server: Part I (use indexing) 2009年06月01日 To ...
- [翻译]比较ADO.NET中的不同数据访问技术(Performance Comparison:Data Access Techniques)
Performance Comparison: Data Access Techniques Priya DhawanMicrosoft Developer Network January 2002 ...
- Apache Cloudstack Development 101 -- Data Access Layer
刚接触CloudStack,也是第一次翻译英文文档,限于水平有限,不当之处欢迎拍砖! 原文地址:https://cwiki.apache.org/confluence/display/CloudSta ...
- Data access between different DBMS and other txt/csv data source by DB Query Analyzer
1 About DB Query Analyzer DB Query Analyzer is presented by Master Genfeng,Ma from Chinese Mainl ...
- DevExpress v17.2新版亮点——Data Access
用户界面套包DevExpress v17.2日前终于正式发布,本站将以连载的形式为大家介绍各版本新增内容.本文将介绍了Data Access v17.2 的新功能,快来下载试用新版本! 新的API可在 ...
随机推荐
- C# 日志系统 log4net 配置及使用
1.引用Dll 版本是:1.2.10.0,下载Dll 2.Web.config文件配置 <?xml version="1.0" encoding="utf-8&qu ...
- 【CF819C】Mister B and Beacons on Field 数学
[CF819C]Mister B and Beacons on Field 题意:外星人盯上了Farmer Jack的农场!我们假设FJ的农场是一个二维直角坐标系,FJ的家在原点.外星人向FJ的农场上 ...
- tomcat启动后,页面浏览时报错 Unable to compile class for JSP的解决方案【原创】
问题描述: tomcat启动后,console正常,console中语句为: 信息: Server startup in 7291 ms 但浏览器访问首页面http://localhost:808 ...
- 关于Thinkphp访问不正常的问题
最近遇见了个蹩脚的问题,我放在服务器的项目(thinkphp框架)只能访问默认路径内容,不管你url怎么写的,他就访问默认那个文件.. 对于有强迫症的我来说实在是欺人太甚!!! 于是乎我就抓耳挠腮了. ...
- 关于webpy模板自动HTML转义的问题
注意: web.py 将会转义任何任何用到的变量,所以当你将 name 的值设为是一段 HTML 时,它会被转义显示成纯文本.如果要关闭该选项,可以写成 $:name 来代替 $name. 如果我们想 ...
- zabbix监控tcp状态
Tcp的连接状态对于我们web服务器来说是至关重要的,从TCP的连接状态中可以看出网络的连接情况,服务器的压力情况,对服务器的并发有很好的直观反映:尤其是并发量ESTAB:或者是syn_recv值,假 ...
- POJ 2676 - Sudoku - [蓝桥杯 数独][DFS]
题目链接:http://poj.org/problem?id=2676 Time Limit: 2000MS Memory Limit: 65536K Description Sudoku is a ...
- Spring 对JDBC操作的支持
1.Spring 对JDBC操作的支持 Spring对jdbc技术提供了很好的支持,体现在: 1.Spring对c3p0连接池的支持很完善 2.Spring对jdbc提供了jdbcTemplate,来 ...
- J - Fire!---UVA 11624
题目链接 题意:J代表Joe的位置,F代表火的起点,下一刻火将会向四周扩散,求Joe逃离的最短时间,如果不能逃离输出IMPOSSIBLE; 注意火的起点可能不止一处 可以用两次bfs分别求出人到达某个 ...
- 洛谷P1850 换教室 [noip2016] 期望dp
正解:期望dp 解题报告: 哇我发现我期望这块真的布星,可能在刷了点儿NOIp之后会去搞一波期望dp的题...感觉连基础都没有打扎实?基础概念都布星! 好那先把这题理顺了嗷qwq 首先我们看到期望就会 ...