儲存過程優缺點-附加簡單例子
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
最後作者希望各位指出作者的不足,畢竟在程式這條路才剛剛起步!