之因此有這個題目,我既不是故意吸引眼球,也不想在本文對存儲過程進行教科書般論述。最近項目中遇到的存儲過程問題,讓我想起了去年在武漢出差時一位同事的發問:java
我以爲存儲過程挺好用的,爲何你不建議用?
當時我好似胸有萬言,但終究沒用一個實在的例子回答同事,只是從結論上大侃一通,代碼相對於SQL,複用、擴展、通用性都要更強。想必同事並不信服。web
如今想來,我最近正碰到的問題,算是一個能夠回答同事的例子吧。數據庫
最近項目中有個新需求,須要校驗一個用戶是否有Job,Certification,Disclosure這三個業務數據。服務器
翻看了代碼發現,系統的用戶我的頁面的C#代碼調用了三個存儲過程,去抓取用戶的Job,Certification,Disclosure數據。
個人新需求,天然須要複用這三個存儲過程,不然:網絡
若每一處都寫一次抓取數據的業務邏輯代碼,若業務邏輯發生變化,難以追查和維護全部讀取Job,Certification,Disclosure的SQL。
若是我在C#代碼中調用這已有的三個存儲過程,事情本該很是快就能結束。我也是這麼作的。性能
但code reviewer認爲,個人需求中,並不須要Job,Certification,Disclosure這三個業務對象的數據。我只是須要給定用戶\_是否\_有Job,Certification,Disclosure而已。因此我應將是否有無Job,Certification,Disclosure的判斷邏輯寫在數據庫,最終經過網絡從數據庫傳到web服務器的僅是true或false,節省網絡流量,這樣最好不過了。學習
也對。除開網絡性能,從接口設計的角度講,接口的傳入和返回值,都應是你自己須要的數據,不該帶有大量不須要或者須要caller去預處理的數據。從接口語義表達就可知調用的目的,這樣代碼可讀性也會有大大提升。ui
那就動手改。但沒想到的是問題來了。spa
爲了講述問題,我簡化代碼,假設系統現有的存儲過程以下:設計
`CREATE PROCEDURE [dbo].[GetJobs]` `(` `@PersonId int,` `@OrganizaitionId int` `)` `AS` `BEGIN` `SELECT JobId,JobName,JobType FROM Job WHERE PersonId = @PersonId AND OrganizaitionId = @OrganizaitionId` `END`
我在新的存儲過程當中調用它,我須要得到該person的jobs的數量,即GetJobs
返回結果集的count。
爲了實現這一目的,首先想到的是使用臨時表,將返回結果集存入臨時表,再對其進行count(*)
的計數操做:
`CREATE PROCEDURE [dbo].[MyProc]` `(` `@PersonId int,` `@OrganizaitionId int,` `)` `AS` `BEGIN` `CREATE TABLE #Temp(` `PersonId int,` `OrganizaitionId int` `)` `INSERT INTO #Temp EXEC dbo.GetJobs` `@PersonId = @PersonId,` `@ParentOrgId = @ParentOrgId` `SELECT COUNT(*) FROM #Temp` `END`
這種辦法簡單有效,但它存在嚴重的維護問題。將來若是被調用的存儲過程的返回結果集字段有變更,那麼MyProc
中的臨時表結構也須要隨之變化。這是使人難以接受的。
那麼將MyProc
中的INSERT INTO換爲SELECT INTO呢?很遺憾,答案是不行。SQL自己並不支持這種用法。
給現有存儲過程GetJobs
加output
參數?本例中由於GetJobs已被其餘多處代碼或SQL scripts調用,因此對現有現有存儲過程進行改動會有不小風險。
我搜遍網絡,一位MS MVP的大神的文章幾乎總結了全部存儲過程之間傳遞數據的方法: How to Share Data between Stored Procedures。他在文章中也迫不得已地說道
Keep in mind that compared to languages such as C# and Java, Transact-SQL is poorly equipped for code reuse, why solutions in T‑SQL to reuse code are clumsier.
最終我沒能找到一種滿意的辦法,無奈之下我在新寫的存儲過程當中將查詢Jobs的語句寫一了次。
存儲過程在不少場景時有其優點,好比性能。但對於業務邏輯的通用方法,很是不推薦將其寫在存儲過程當中,代碼複用、擴展與客戶端語言比,相差甚遠。也許終究能實現,但代價與風險比客戶端語言要高,得不償失。
天知道還有沒有機會和那位前同事再討論這一話題呢。