1. <strong id="7actg"></strong>
    2. <table id="7actg"></table>

    3. <address id="7actg"></address>
      <address id="7actg"></address>
      1. <object id="7actg"><tt id="7actg"></tt></object>

        我覺得存儲過程挺好用的,為什么你不建議用?

        共 2272字,需瀏覽 5分鐘

         ·

        2020-09-09 20:48

        來源:sf.ggs/a/1190000011138993

        之所以有這個題目,我既不是故意吸引眼球,也不想在本文對存儲過程進行教科書般論述。最近項目中遇到的存儲過程問題,讓我想起了去年在武漢出差時一位同事的發(fā)問:

        我覺得存儲過程挺好用的,為什么你不建議用?

        當時我好似胸有萬言,但終究沒用一個實在的例子回答同事,只是從結論上大侃一通,代碼相對于SQL,復用、擴展、通用性都要更強。想必同事并不信服。

        現在想來,我最近正碰到的問題,算是一個可以回答同事的例子吧。

        最近項目中有個新需求,需要校驗一個用戶是否有Job,Certification,Disclosure這三個業(yè)務數據。

        翻看了代碼發(fā)現,系統的用戶個人頁面的C#代碼調用了三個存儲過程,去抓取用戶的Job,Certification,Disclosure數據。我的新需求,自然需要復用這三個存儲過程,否則:

        若每一處都寫一次抓取數據的業(yè)務邏輯代碼,若業(yè)務邏輯發(fā)生變化,難以追查和維護所有讀取Job,Certification,Disclosure的SQL。

        如果我在C#代碼中調用這已有的三個存儲過程,事情本該非??炀湍芙Y束。我也是這么做的。

        但code reviewer認為,我的需求中,并不需要Job,Certification,Disclosure這三個業(yè)務對象的數據。我只是需要給定用戶是否有Job,Certification,Disclosure而已。所以我應將是否有無Job,Certification,Disclosure的判斷邏輯寫在數據庫,最終通過網絡從數據庫傳到web服務器的僅是true或false,節(jié)省網絡流量,這樣最好不過了。也對。除開網絡性能,從接口設計的角度講,接口的傳入和返回值,都應是你本身需要的數據,不應帶有大量不需要或者需要caller去預處理的數據。從接口語義表達就可知調用的目的,這樣代碼可讀性也會有大大提高。

        那就動手改。但沒想到的是問題來了。

        為了講述問題,我簡化代碼,假設系統現有的存儲過程如下:

        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本身并不支持這種用法。

        給現有存儲過程GetJobsoutput參數?本例中因為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的語句寫一了次。

        存儲過程在很多場景時有其優(yōu)勢,比如性能。但對于業(yè)務邏輯的通用方法,非常不推薦將其寫在存儲過程中,代碼復用、擴展與客戶端語言比,相差甚遠。也許終究能實現,但代價與風險比客戶端語言要高,得不償失。

        天知道還有沒有機會和那位前同事再討論這一話題呢。

        - 推薦閱讀 -


        架構師離職后,成為自由開發(fā)者的第 100 天


        下方二維碼關注我

        互聯網草根,堅持分享技術、創(chuàng)業(yè)、產品心得和總結~



        點擊“閱讀原文”,領取 2020 年最新免費技術資料大全

        ↓↓↓?
        瀏覽 44
        點贊
        評論
        收藏
        分享

        手機掃一掃分享

        分享
        舉報
        評論
        圖片
        表情
        推薦
        點贊
        評論
        收藏
        分享

        手機掃一掃分享

        分享
        舉報
        1. <strong id="7actg"></strong>
        2. <table id="7actg"></table>

        3. <address id="7actg"></address>
          <address id="7actg"></address>
          1. <object id="7actg"><tt id="7actg"></tt></object>
            岳每晚被弄嗷嗷高潮视频 | 好大好长好紧好爽 | 日本一区视频在线 | freehdxxxxjapanmovie | 性船1980未删版90分钟免费观看 | 国产精华7777777 | 国产毛片一区二区三区 | 欧美妞老逼视频 | freeexxx性欧美 | 就要操逼网站 |