1. 程式人生 > >儲存過程優缺點-附加簡單例子

儲存過程優缺點-附加簡單例子

1、什麼是儲存過程?

       儲存過程(Stored Procedure)是在大型資料庫系統中,一組為了完成特定功能的SQL 語句集,儲存在資料庫中,經過第一次編譯後呼叫不需要再次編譯,使用者通過指定儲存過程的名字並給出引數(如果該儲存過程帶有引數)來執行它。儲存過程是資料庫中的一個重要物件。

2、儲存過程的優點:

        A、 儲存過程允許標準組件式程式設計

        儲存過程建立後可以在程式中被多次呼叫執行,而不必重新編寫該儲存過程的SQL語句。而且資料庫專業人員可以隨時對儲存過程進行修改,但對應用程式原始碼卻毫無影響,從而極大的提高了程式的可移植性。

        B、 儲存過程能夠實現較快的執行速度

        如果某一操作包含大量的T-SQL語句程式碼,分別被多次執行,那麼儲存過程要比批處理的執行速度快得多。因為儲存過程是預編譯的,在首次執行一個儲存過程時,查詢優化器對其進行分析、優化,並給出最終被存在系統表中的儲存計劃。而批處理的T-SQL語句每次執行都需要預編譯和優化,所以速度就要慢一些。

        C、 儲存過程減輕網路流量

        對於同一個針對資料庫物件的操作,如果這一操作所涉及到的T-SQL語句被組織成一儲存過程,那麼當在客戶機上呼叫該儲存過程時,網路中傳遞的只是該呼叫語句,否則將會是多條SQL語句。從而減輕了網路流量,降低了網路負載。

        D、 儲存過程可被作為一種安全機制來充分利用

        系統管理員可以對執行的某一個儲存過程進行許可權限制,從而能夠實現對某些資料訪問的限制,避免非授權使用者對資料的訪問,保證資料的安全。

   E、可擴充套件性:應用程式和資料庫操作分開,獨立進行,而不是相互在一起。方便以後的擴充套件和DBA維護優化。

  總述:執行快、減少網路傳輸、可以維護性強、加強安全性、可擴充套件性強

3、儲存過程的缺點:

   A. SQL本身是一種結構化查詢語言,但不是面向物件的的,本質上還是過程化的語言,面對複雜的業務邏輯,過程化的處理會很吃力。同時SQL擅長的是資料查詢而非業務邏輯的處理,如果如果把業務邏輯全放在儲存過程裡面,違背了這一原則。

   B. 如果需要對輸入儲存過程的引數進行更改,或者要更改由其返回的資料,則您仍需要更新程式集中的程式碼以新增引數、更新呼叫,等等,這時候估計會比較繁瑣了。

   C. 開發除錯複雜,由於IDE的問題,儲存過程的開發除錯要比一般程式困難。     

   D. 沒辦法應用快取。雖然有全域性臨時表之類的方法可以做快取,但同樣加重了資料庫的負擔。如果快取併發嚴重,經常要加鎖,那效率實在堪憂。

   E. 不支援群集,資料庫伺服器無法水平擴充套件,或者資料庫的切割(水平或垂直切割)。資料庫切割之後,儲存過程並不清楚資料儲存在哪個資料庫中。

  總述:編寫複雜度高、邏輯性強、更改不便等

4、優缺點總述:

  1、我們要適當的使用儲存過程來提高我們查詢的質量,如複雜的連線查詢等

  2、避免濫用,因為開發儲存過程需要時間,避免複雜的邏輯而去使用儲存過程,減少資料庫的壓力

5、資料庫中的儲存過程有二部分:

  1、系統儲存過程:系統儲存過程是系統建立的儲存過程以“sp”下劃線開頭的儲存過程一般存放在master資料庫中,其目的是為了幫助我們呼叫、更新和管理系統相關的資訊。

exec sp_databases; --檢視資料庫
exec sp_tables;        --查看錶
exec sp_columns student;--檢視列
exec sp_helpIndex student;--檢視索引
exec sp_helpConstraint student;--約束
exec sp_stored_procedures;
exec sp_helptext 'sp_stored_procedures';--檢視儲存過程建立、定義語句
exec sp_rename student, stuInfo;--修改表、索引、列的名稱
exec sp_renamedb myTempDB, myDB;--更改資料庫名稱
exec sp_defaultdb 'master', 'myDB';--更改登入名的預設資料庫
exec sp_helpdb;--資料庫幫助,查詢資料庫資訊
exec sp_helpdb master;

  2、使用者自定義的儲存過程:

  基本語法:

create proc | procedure pro_name
    [{@引數資料型別} [=預設值] [output],
     {@引數資料型別} [=預設值] [output],
     ....
    ]
as
    SQL_statements

  不帶引數的儲存過程語法

if (exists (select * from sys.objects where name = 'proc_name'))
    drop proc proc_name
go
create proc proc_name
as
    select * from student;

--呼叫、執行儲存過程
exec proc_name;

  掌握了基本語法之後,試著去寫幾個複雜的儲存過程,在實際應用中還是有很多好處的,畢竟對於後端開發工程師來說:這是一個必經之路,當然對於DBA(資料庫管理員)來說,這個都是非常EASY的事情

  最後作者在奉獻一個我在開發中寫的一個儲存過程:非常簡單希望各位大神不要笑(*^_^*)

  這是一個紅酒檢驗檢疫查詢

展示儲存過程

CREATE PROC [dbo].[Proc_Check_Checkout] 
    @pageIndex AS INT,
    @pageSize AS INT,
    @ForecastBegin AS NVARCHAR(MAX),--預檢
    @ForecastEnd AS NVARCHAR(MAX),
    @InspectionBegin AS NVARCHAR(MAX),--報檢
    @InspectionEnd AS NVARCHAR(MAX), 
    @CheckoutID AS NVARCHAR(MAX),--預檢單號
    @InspectionID AS NVARCHAR(MAX),--報檢單號
    @recordCount  AS INT OUTPUT
AS
    SET NOCOUNT ON
    DECLARE @tempPageSize INT;
    SET @tempPageSize = (@pageIndex - 1) * @pageSize;

 SELECT 
 --第一二條查詢
 t1.ID,t2.CheckoutID,t1.QuarantineID,t1.PurchaseContract,t1.Origin,t1.Consignee,t1.GoodsName,t1.Bottle,t1.Numbers,t1.RiseNumber,t1.Mount,CONVERT(NVARCHAR(16),t1.ForecastDate,20) AS ForecastDate,
 t2.InspectionID,t2.KBottle,t2.KNumbers,t2.KRiseNumber,
 --三四條查詢
 t2.Franchisee,t2.Brand,t2.BottleInspection,t2.NewspaperNumber,t2.NumberInspection,t2.CheckMount,CONVERT(NVARCHAR(16),t2.HisDate,20) AS HisDate,t2.InspectionDate
 INTO #TempData1
 FROM dbo.TBPreview_Table AS t1 

 LEFT JOIN dbo.TBCheckout AS t2 ON t2.CheckoutID = t1.ID
 ORDER BY t1.Date DESC ;


 SELECT * INTO #TempData2 FROM #TempData1 WHERE 1 = 2;

 --時間檢索 
 IF @ForecastBegin IS NOT NULL AND LEN(@ForecastBegin) > 0
 BEGIN
        TRUNCATE TABLE #TempData2;
        INSERT INTO #TempData2 
        SELECT *FROM #TempData1 AS t WHERE t.ForecastDate >= @ForecastBegin;
        TRUNCATE TABLE #TempData1;
        INSERT INTO #TempData1 SELECT * FROM #TempData2;
 END
 
 --
 IF @ForecastEnd IS NOT NULL AND LEN(@ForecastEnd) > 0
 BEGIN
        TRUNCATE TABLE #TempData2;
        INSERT INTO #TempData2 
        SELECT *FROM #TempData1 AS t WHERE t.ForecastDate < DATEADD(DAY,1,@ForecastEnd) ;
        TRUNCATE TABLE #TempData1;
        INSERT INTO #TempData1 SELECT * FROM #TempData2;
 END
 
 --時間檢索 報檢時間
 IF @InspectionBegin IS NOT NULL AND LEN(@InspectionBegin) > 0
 BEGIN
        TRUNCATE TABLE #TempData2;
        INSERT INTO #TempData2 
        SELECT *FROM #TempData1 AS t WHERE t.InspectionDate >= @InspectionBegin;
        TRUNCATE TABLE #TempData1;
        INSERT INTO #TempData1 SELECT * FROM #TempData2;
 END
 
 --
 IF @InspectionEnd IS NOT NULL AND LEN(@InspectionEnd) > 0
 BEGIN
        TRUNCATE TABLE #TempData2;
        INSERT INTO #TempData2 
        SELECT *FROM #TempData1 AS t WHERE t.InspectionDate < DATEADD(DAY,1,@InspectionEnd) ;
        TRUNCATE TABLE #TempData1;
        INSERT INTO #TempData1 SELECT * FROM #TempData2;
 END
 
 /* 預檢單號 */
  IF @CheckoutID IS NOT NULL AND LEN(@CheckoutID) > 0
 BEGIN
        TRUNCATE TABLE #TempData2;
        INSERT INTO #TempData2 
        SELECT *FROM #TempData1 AS t WHERE t.QuarantineID LIKE '%'[email protected]+'%' ;
        TRUNCATE TABLE #TempData1;
        INSERT INTO #TempData1 SELECT * FROM #TempData2;
 END

 /* 報檢單號*/
   IF @InspectionID IS NOT NULL AND LEN(@InspectionID) > 0
 BEGIN
        TRUNCATE TABLE #TempData2;
        INSERT INTO #TempData2 
        SELECT *FROM #TempData1 AS t WHERE t.InspectionID LIKE '%'[email protected]+'%' ;
        TRUNCATE TABLE #TempData1;
        INSERT INTO #TempData1 SELECT * FROM #TempData2;
 END

SELECT @recordCount = COUNT(1) FROM #TempData1;
    DROP TABLE #TempData2;
    SELECT * INTO #TempData3 FROM #TempData1 WHERE 1 = 2;
    INSERT INTO #TempData3
    SELECT TOP (@pageSize) t1.* FROM #TempData1 AS t1 , 
    (SELECT * , ROW_NUMBER() OVER (ORDER BY ID) AS RowNumber FROM #TempData1) AS t2
    WHERE t1.ID = t2.ID AND RowNumber > @tempPageSize 
    ORDER BY t2.RowNumber;
    DROP TABLE #TempData1;
    SELECT * FROM #TempData3;
GO

最後作者希望各位指出作者的不足,畢竟在程式這條路才剛剛起步!