問題的提出
當你在開發乙個基於資料庫的應用的時候,你可能會想這樣乙個問題:資料庫有關的事務操作部分因該放在那裡?是以儲存過程(stored procedure)的形式放在資料庫端呢,還是將查詢以及相應運算嵌在應用程式當中呢?要回答這樣乙個問題,你首先要了解儲存過程以及內嵌t-sql這兩種方案各自的優缺點以及他們分別適用的場合。尤其是在新的.net開發環境中,如何選取正確的解決方案是非常關鍵的。
為什麼要使用儲存過程(stored procedures)?
你可能對資料庫程式設計已經有一些經驗了,對sqlcommand物件也比較熟悉了。但是你是否想過你的這些資料庫相關的操作是不是符合優化原則呢?那些相對複雜的資料處理是應當嵌在應用程式中呢,還是把它封裝在儲存過程中,放置在資料庫端?
再展開討論之前,讓我們先簡要的回顧一下儲存過程的概念。
儲存過程是一組t-sql語句,它們存放在一起形成一段t-sql程式。在執行的時候,你可以傳入一些引數;你得到的可以是結果集合(result set),也可以是輸出引數(output parameters),甚至是返回值(return value)。儲存過程在第一次被執行的時候,資料庫系統要首先對它進行分析和編譯。編譯後得到了乙個執行計畫(execution plan)。所謂執行計畫就是資料庫具體執行這個儲存過程的先後步驟的過程紀錄。這個編譯得到的執行計畫被放置到資料庫的快取池中以備以後再次使用。如果這個儲存過程今後再次被呼叫,那麼資料庫將從快取池中取出這個執行計畫來執行。這樣就避免了重複對該儲存過程進行再次分析和編譯,從而提高了資料庫的效能。(這些快取池中的執行計畫將一直被儲存著,直到資料庫重新啟動或是系統記憶體不夠用而被清除出快取池)。
是否使用儲存過程,我們可以從以下三個方面來進行分析。
一.效能(performance)
在以前,儲存過程比查詢(query)有效能上的優勢。原因是資料庫會快取儲存過程的執行計畫(execution plan)。但是在最近的sql資料庫7.0以後的版本中,查詢的執行計畫也被資料庫放到快取池中。這樣一來儲存過程的傳統優勢就不再存在了。只要你的查詢語句是靜態的(static)並且你經常使用它,這樣他就不會被資料庫清理出快取池去。如果它的執行計畫得到重用,那麼理論上講查詢和儲存過程沒有效能上的區別。要注意的一點是,查詢的語句必須保持靜態,如果你更動了一些,哪怕是很不重要的乙個部分,那麼這個查詢很可能在快取池裡找不到匹配的執行計畫。那麼查詢只好被資料庫重新編譯,這將導致效能上的損失。
不過在網路傳輸方面,儲存過程比查詢仍然占有優勢。因為使用儲存過程只需要向資料庫傳遞儲存過程的名字和必要的引數,而不是像查詢那樣要傳輸全部查詢語句。如果查詢邏輯複雜的話,那麼查詢語句的大小也將會比較可觀。另外,設計合理的儲存過程可以減少客戶端和資料庫端之間的往返,甚至減少到一次。
另外,通過使用遠端過程呼叫(remote procedure calls, rpc)來執行資料庫端的儲存過程可以加強執行計畫的重用性,從而提高效能。當你指定sqlcommand.commandtype為storedprocedure的時候,儲存過程是通過rpc來執行的。rpc包裝整理引數然後呼叫資料庫的儲存過程的方式使得資料庫引擎非常容易發現匹配的執行計畫。你在呼叫該儲存過程時可以使用了不同的引數,資料庫系統將會使用同乙個執行計畫的。
在決定是否使用儲存過程的時候,你還要判斷你的特定操作是不是利用了儲存過程的長處。總體來說:
" 基於集合的運算(set-based)是t-sql的強項
" 基於行的運算(row-based)以及基於字串的運算(string manipulation)不是t-sql的強項。至少在下乙個版本yukon資料庫出來之前,你應當避免這樣的操作。
也就是說,有些操作由應用程式的高階語言來完成往往會比資料庫來往成更有效。比如比較複雜的字串處理。這時候,將所有的操作全部放到儲存過程中就不是乙個最優化的辦法。你可能要合理的劃分任務,讓資料庫和應用程式各自完成其擅長的任務。
二.可維護性和抽象能力(maintainability and abstraction)
使用儲存過程另外乙個潛在的好處就是可維護性好。儘管我們希望資料庫結構永遠不要變動,事務處理規則也永遠保持不變,但事實上這是不大可能發生的。對於好多更動,你也許只需要更改儲存過程的具體實現就可以完成。所有使用它的客戶端程式就不需要重新修改,除錯和編譯。這樣很多變動對於客戶程式來說就是透明的(transparent)。在大多情況下,這種辦法往往是最有效和最簡單的。
另外,通過抽象具體實現(implementation)和將t-sql語句放在儲存過程中,可以使任何客戶端呼叫者以乙個統一的形式來訪問資料。從全域性上看,一種資料操作運算只有一種實現,放在乙個地方。這樣更改和維護都將非常方便。不同的使用者也將永遠得到同一樣的結果。
使用儲存過程的另外乙個維護性方面的好處是你可以有更好的程式版本控制。你可以使用版本控制的軟體來幫助你維護儲存過程,就象你維護其它源程式那樣。比如,你可以使用微軟的visual sourcesafe?來幫你做到這一點。這樣你可以很方便的找回以前任何乙個版本的儲存過程。
需要指出的一點是使用儲存過程不能防止你修改資料庫結構和事務處理規則。如果更動比較大,需要重新設計傳入的引數或者返回值,那麼你將需要修改客戶端呼叫這些儲存過程的程式段。
你應該考慮到使用儲存過程來封裝你的事務處理邏輯將影響應用的可移植性。儲存過程是和sql資料庫**在一起的,如果你想更換資料庫平台,你可能要重寫這些儲存過程。如果可移植性對你的應用的是非常關鍵的,那麼將事務處理邏輯放在資料庫系統中立(rdbms-neutral)的中間層(middle-tier)比較好。
三.安全性(security)
最後乙個使用儲存過程的原因是它可以增強資料庫系統的安全性。
從管理使用者訪問資訊角度來講,它可以通過讓使用者訪問一定的儲存過程來保證使用者可以訪問特定的資料,這是一種間接的資料訪問,而不是直接對使用者開放式據庫**。其實我們可以將儲存過程假想為資料庫系統的view。唯一的區別就是儲存過程可以變更引數而使得結果動態變化。
儲存過程還可以讓你在程式安全性方面有所改進。它可以防備一種叫做sql注入式的攻擊(sql injection attacks)- 這種攻擊主要是用and或是or運算子將命令拼接在有效的輸入引數之後。儲存過程還可以隱藏事務處理規則於資料庫端,而不是放在客戶程式端。在有些情況下(比如涉及到智財權等等),這種隱藏是非常重要的。
此外,使用儲存過程可以讓你使用ado.net提供的sqlparameter類。你可以使用這個類來說明具體的引數型別。這使得你更加容易來驗證使用者輸入的引數是否合法。引數對於儲存過程和in-line查詢來說是同樣重要的,它可以將使用者的輸入降低到乙個很小的範圍內。
當然使用儲存過程並不意味著安全方面你可以高枕無憂了。事實上,不好的程式以及資料庫管理方面的漏洞仍然可以將你置於可能的攻擊之中。如果對sql資料庫的角色(role)建立以及授權不當,那麼將導致使用者可以訪問一些他們本不應該訪問的資料。同樣,僅僅使用儲存過程並不能完全保證不受sql注入式攻擊。
另外使用sqlparameter類來校驗使用者輸入也不是絕對安全的,不管是在後台t-sql寫的儲存過程中還是嵌在應用中的查詢,所有使用者的輸入,尤其是字串型別的資料,一定要在交給資料庫引擎處理之前進行有效性的校驗。
儲存過程適用於你嗎?
綜上所述,使用儲存過程有如下幾個突出優點:
" 提高新能,減少了網路流量
" 在資料庫端一點的維護(single point of maintenance )
" 抽象和概化業務邏輯,增強了一致性和安全性
" 減少了一些可能的惡意攻擊的機會
" 鼓勵執行計畫的重用性(encourage execution plan re-use )
如果你的應用程式能有效的利用儲存過程的上述優點,那麼你就應該盡量使用。但是如果你的應用要求有很高的可移植性,或者資料庫的結構變動很大,不能相對穩定下來,那麼你可能要試一試其他方法了。比如你現在在sql資料庫上為使用者開發乙個早期可行性驗證程式,今後使用者很可能使用mysql或是oracle等其它資料庫,那麼你就因該避免使用sql資料庫的儲存過程,而使用程式內嵌的資料庫操作語句。這樣當你更換資料庫平台的時候,可以極大的保證程式不受影響。
另外,你還要考慮使用儲存過程的技術問題。也許你和你的手下非常不熟悉儲存過程程式設計,並且沒有時間去很快掌握它。這些因素你也需要通盤考慮。另外如前所述,資料庫儲存過程擅長於基於集合(set-based)的操作,而不擅長基於行(row-based)的操作。如果你對儲存過程沒有很好的了解,而不正確的使用了它往往會導致很不好的執行效能。所以如果你決定使用儲存過程,那麼多花一些時間來學習它是很有必要的。
為什麼要使用儲存過程?
1.儲存過程只在創造時進行編譯,以後每次執行儲存過程都不需再重新編譯,而一般 sql 語句每執行一次就編譯一次,所以使用儲存過程可提高資料庫執行速度。2.當對資料庫進行複雜操作時 如對多個表進行 update,insert,query,delete 時 可將此複雜操作用儲存過程封裝起來與資料庫提供的...
使用QSettings儲存QT應用程式資料
qsettings類提供了持久的跨平台應用程式設定,這些settings一般都是存在系統裡的,比如windows一般都寫在系統登錄檔或者寫ini檔案,mac系統一般都在xml檔案裡,那麼按照一般的標準來說,許多應用程式是用ini檔案來實現的。而qsettings就是提供了一種方便的方法來儲存和恢復應...
QT中使用QSettings儲存應用程式配置資訊
使用qt中的qsettings中的一些方法,以下是我的一些簡單的應用方面,經過測試可行。首先我new了這麼乙個兩個物件,乙個物件我是用來寫入配置檔案的,乙個物件我是用來讀取配置檔案中資訊的 qt中使用qsettings類讀寫ini檔案 qsettings建構函式的第乙個引數是ini檔案的路徑,第二個...