http://www.cnblogs.com/yangzhong/archive/2010/12/01/1893137.html
存儲過程一般用於處理比較複雜的任務,基礎ms這個平臺,可以大大降低耗時,其編譯機制也提高了數據庫執行速度。
當然在系統控制方便方面,例如當系統進行調整時,這是隻需要將後臺存儲過程進行更改,而不需要更改客戶端程序。也無需重新安裝客戶端應用程序。
存儲過程不僅僅適用於大型項目,對於中小型項目,使用存儲過程也是非常有必要的。其威力和優勢主要體現在:
1.存儲過程只在創造時進行編譯,以後每次執行存儲過程都不需再重新編譯,而一般 SQL 語句每執行一次就編譯一次,所以使用存儲過程可提高數據庫執行速度。
(這涉及到原理性的問題,你記住就好!)
2.當對數據庫進行復雜操作時(如對多個表進行Update,Insert,Query,Delete 時),可將此複雜操作用存儲過程封裝起來與數據庫提供的事務處理結合一起使用。這些操作,如果用程序來完成,就變成了一條條的 SQL 語句,可能要多次連接數據庫。而換成存儲,只需要連接一次數據庫就可以了。
(儘可能少的連接數據庫,可以減少時間損耗;事務方面在批量操作中非常重要,因爲事務可以回溯,當出錯時,可以進行回溯,保證數據的完整性!)
3.存儲過程可以重複使用,可減少數據庫開發人員的工作量。
(體現在分頁存儲過程,以及下面這個例子:)
例子:create PROC [dbo].[jobs_public_select]
@TableName VARCHAR(2000),/*表名*/
@ParamName VARCHAR(2000),/*查詢字段字符串*/
@ParamWhere NVARCHAR(2000)/*條件字符串*/
AS
BEGIN
Declare @SQL varchar(500)
set @SQL='SELECT '+@ParamName+' from '+@TableName+' WHERE 1=1'
IF @ParamWhere<>''
BEGIN
SET @SQL=@SQL+@ParamWhere
END
exec(@SQL)
END
(這個例子主要作用就是公共查詢功能,你只需要傳遞表名,查詢的字段,條件即可。你可以以此類推,寫個公共刪除,公共更新的;操作無非也這幾種哈。)
4.安全性高,可設定只有某此用戶才具有對指定存儲過程的使用權。
(這方面在賦權限,主要體現在,連接時採用哪個用戶連接數據庫,而對應的這個用戶也有對應的數據庫操作權限。)
優點:
1.速度快。尤其對於較爲複雜的邏輯,減少了網絡流量之間的消耗
我有的過程和函數達到了幾百行,一個微型編譯器,相信用程序就更麻煩了。
(在獲取權限那個存儲過程深有體會,你也可以寫個C#的算法,然後與存儲過程進行速度比較。)
2.寫程序簡單,採用存儲過程調用類,調用任何存儲過程都只要1-2行代碼。
(我不知道別人怎麼調用,我是深受其益)
3.升級、維護方便(你只需要更改存儲過程就好,比如添加一個字段等)
4.調試其實也並不麻煩,可以用查詢分析器(基礎好,一般沒有遇到很大的錯誤!)
5.如果把所有的數據邏輯都放在存儲過程中,那麼asp.net只需要負責界面的顯示阿什麼的,出錯的可能性最大就是在存儲過程。我碰到的就一般是這種情況。
(減少了排錯的時間)
缺點:
1.可移植性差,我一直採用sql server開發,可是如果想賣自己的東西,發現自己簡直就是在幫ms賣東西,呵呵。想換成mysql,確實移植麻煩。
2.採用存儲過程調用類,需要進行兩次調用操作,一次是從sql server中取到過程的參數信息,並且建立參數;第二次纔是調用這個過程。多了一次消耗。
不過這個缺點可以在項目開發完成,過程參數完全確定之後,把所有過程參數信息倒入到一個xml文件中來提高性能。
當一個業務同時對多個表進行處理的時候採用存儲過程比較合適。
1. 使用存儲過程在一般情況下會提高性能,因爲數據庫優化了存儲過程的數據訪問計劃並應用緩存方便以後的查詢;
2. 存儲過程單獨保護存在於數據庫中。客戶端可以獲取權限執行存儲過程,而不需要對底層的具體表設置其他的訪問權限;
3. 存儲過程會使得維護起來更加方便,因爲通常修改一個存儲過程要比在一個已經發布的組件中修改SQL語句更加方便;
4. 存儲過程給底層數據格式增添了額外的抽象層。使得使用存儲過程的客戶端對存儲過程的實現細節以及對底層數據格式是隔離獨立的;
5. 存儲過程能夠緩解網絡帶寬,因爲可以批量執行SQL語句而不是從客戶端發送超負載的請求。
複雜的數據處理用存儲過程,如有些報表處理
多條件多表聯合查詢,並做分頁處理
總結:
1. 當一個事務涉及到多個SQL語句時或者涉及到對多個表的操作時就要考慮用存儲過程;
2. 當在一個事務的完成需要很複雜的商業邏輯時(比如,對多個數據的操作,對多個狀態的判斷更改等)要考慮;
3. 還有就是比較複雜的統計和彙總也要考慮,但是過多的使用存儲過程會降低系統的移植性。
分頁例子:
create procedure [dbo].[sp_super_page]
@TableName varchar(5000), --要進行分頁的表,也可以用聯接,如dbo.employee或dbo.employee INNER JOIN dbo.jobs ON (dbo.employee.job_id=dbo.jobs.job_id)
@Fields varchar(5000), --表中的字段,可以使用*代替
@OrderField varchar(5000), --要排序的字段
@sqlWhere varchar(5000), --WHERE子句
@pageSize int,--分頁的大小
@pageIndex int,--要顯示的頁的索引
@TotalPage int output, --頁的總數
@TotalRecords int output--信息總條數
as
begin
Begin Tran
Declare @sql nvarchar(4000);
Declare @totalRecord int; --記錄總數
if (@sqlWhere IS NULL or @sqlWhere = '')
--在沒有WHERE子句的情況下得到表中所有的記錄總數
set @sql = 'select @totalRecord = count(*) from ' + @TableName
else
--利用WHERE子句進行過濾
set @sql = 'select @totalRecord = count(*) from ' + @TableName + ' where ' + @sqlWhere
--執行sql語句得到記錄總數
EXEC sp_executesql@sql,N'@totalRecord int OUTPUT',@totalRecord OUTPUT
select @TotalPage=CEILING((@totalRecord+0.0)/@PageSize)
--根據特定的排序字段爲爲行分配唯一ROW_NUMBER的順序
if (@sqlWhere IS NULL or @sqlWhere = '')
set @sql = 'select * from (select ROW_NUMBER() over(order by ' + @OrderField + ') as rowId,' + @Fields + ' from ' + @TableName
else
set @sql = 'select * from (select ROW_NUMBER() over(order by ' + @OrderField + ') as rowId,' + @Fields + ' from ' + @TableName + ' where ' + @SqlWhere
--確保當前頁的索引在合理的範圍之內
if @PageIndex<=0
Set @pageIndex = 1
if @pageIndex>@TotalPage
Set @pageIndex = @TotalPage
--得到當前頁在整個結果集中準確的ROW_NUMBER值
Declare @StartRecord int
Declare @EndRecord int
set @StartRecord =(@pageIndex-1)*@PageSize + 1
set @EndRecord = @StartRecord + @pageSize - 1
--輸出當前頁中的數據
set @Sql = @Sql + ') as t' + ' where rowId between '+ Convert(varchar(50),@StartRecord) + ' and ' + Convert(varchar(50),@EndRecord)
Exec(@Sql)
If @@Error <> 0
Begin
RollBack Tran
SET @TotalRecords=-1
End
Else
Begin
Commit Tran
SET @TotalRecords=@totalRecord
End
end