標籤:
SQL譯為按每一次情況的辦理,SP意為預存程序,ORM就是對象-關係映射,比如Hibernate
一,演變
剛開始的時候,只有sql語句,即可以用互動模式一句一句執行, 也可以用批模式執行,多行sql語句一次提交執行。
很快人們發現用批模式執行的一堆sql語言可以用過程的形式,事先存放到資料庫裡面,這就變成了預存程序。
隨著物件導向技術的成熟,從程式中可以自動產生sql語句,這就是ORM
二,效能
如果我們把一堆sql,以批的方式一次送入到伺服器,那麼伺服器,會對這一堆sql進行緩衝,當下一次再度執行的時候,就好像調用一個”匿名“的預存程序一樣。在這種情況下,效能差不多。
但是,如果我們不注意,很有可能,把可以一次提交的sql,變成了多次提交,甚至是每個迴圈做了一次提交,那麼效能就很差了,也就是說如果使用sql,只要寫法得當,效能和sp區別不大。
同樣的道理,ORM的效能取決於ORM的Sql產生演算法, 和使用者使用的時候,對產生演算法的控制,比如利用好Lazy laoding等,在某些情況下,甚至可以不通過sql,畢竟沒有sql比最佳化的sql還要快。
三,可維護性
可維護性是選擇sql,sp,orm最主要的因素。
剛開始的時候,sql的維護性看起來是最差,因為它往往散布在程式的每個角落。而儲存過陳都放在資料庫中,有清晰介面。
但是如果我們做一次重構,情況居然會顛倒過來。
首先,預存程序完全可以照搬到C#中,sp的名字直接變成method的名字,sp的參數表直接變成method的參數表,(其實就是Command模式)。
其次,把這些methdod放到一個檔案或者檔案夾中。(所謂的DAL層,如果喜歡層的話)
通過這個重構,我們獲得了以下的好處,
1,首先是過程的調用和過程的定義放到了一起,修改起來比較方便。IDE都有定義跳轉功能。
2,過程的調用和定義同時進資料列版本設定,不會出現不匹配的情況。減少了sp的參數表和調用的不匹配,包括拼字,類型,參數次序
3,單元測試非常方便
當然sp也有存在的價值,比如所謂的安全性,後面會提到。比如友好的調試環境,對於中小型項目,和初級程式員來說,也是很好的選擇。
ORM則將可維護性提升身到了一個新的高度,它試圖將sql屏蔽起來,在操作對象的同時,自動就把資料庫的事情給辦了。
ORM有兩種模式,一種是ActiveRecord, 一種是Datamapper,前者從資料庫中讀取定義,後者在程式中定義。不過由於前者往往用migration來產生資料庫,其實也是定義在程式裡面的。好的ORM都有"leaking"的設計,也就是留了個”後門“,讓你有機會用sql來控制。
微軟的linq從某個角度類說,也是一種ORM, 它的設計思想可能是因為它覺得寫sql語句比寫c#代碼效率高,所以提供直接在C#中寫sql語句的機制,再自動產生真正的sql。不過,ORM真正價值在於它可以在恰當的時候,完全拋棄sql,比如比如讀用cache,寫用queue。而微軟的linq,完全是“無厘頭”的風格,在O中用R的寫法,難道是RRM, 唯一的好處只是鎖定程式和程式員在微軟的平台上。
三,安全性
對企業來說,安全性有的時候比效能更重要,由於預存程序在資料庫上多加了一道屏障,所以很多企業會把預存程序作為首選。
ORM可以說是安全性最差的, 因為只有到程式運行起來,你才能知道,會產生什麼樣的sql。
但是保證安全有許多方法和方面,比如部署前的測試, 資料庫的備份,對錶的許可權的設定。等。用sp來保證安全,只是多個選項中的一個。
在startup型企業中,進階程式員往往起到主導作用, 所以他們會不猶豫的選擇ORM。
在傳統企業中,如果DBA或者技術主管比較強勢,往往會採用sp。
綜上所述:
| |
ORM |
SQL |
| 開發速度 |
快 |
慢 |
| 運行效能 |
慢 |
快 |
| 方便修改 |
|
|
| 可維護性 |
高 |
低 |
ORM,最大的問題是複雜查詢,可以考慮SQL和ORM兩者同時使用,簡單地方用ORM,複雜地方用SQL;利用Cache等技術可以很好地提高查詢速度,在Phalcon中,就是採用兩者合用的方式:
1.Model中返回的是當前的Model集2.PHQL中返回的是查詢集前者支援魔術方法get/count加關聯Model名,用選擇性參數來進行二次篩選;後者採用類似SQL的方法來關聯表,這樣查詢集裡面就利用駝峰規則就可以訪問所有的欄位:$phql = "SELECT Cars.*, Brands.* FROM Cars, Brands WHERE Brands.id = Cars.brands_id"$rows = $manager->executeQuery($phql);foreach ($rows as $row) { echo "Car: ", $row->cars->name, "\n"; echo "Brand: ", $row->brands->name, "\n";}還可以訪問指定欄位:$phql = "SELECT Cars.name AS car_name, Brands.name AS brand_name WHERE Brands.id = Cars.brands_id";$rows = $manager->executeQuery($phql);foreach ($rows as $row) { echo $row->car_name, "\n"; echo $row->brand_name, "\n";}當然可以加別名訪問:$phql = "SELECT c.*, b.* FROM Cars c, Brands b WHERE b.id = c.brands_id";$rows = $manager->executeQuery($phql);foreach ($rows as $row) { echo "Car: ", $row->c->name, "\n"; echo "Brand: ", $row->b->name, "\n";}
SQL,SP與ORM