- 標量函數,當使用T-SQL實現時不能返回rowversion、cursor、table,當使用托管代碼實現時,不能返回rowversion、cursor、table、text、ntext、image
- 創建標量函數時,CREATE FUNCTION必須是批處理中唯一語句;和存儲過程不同,使用函數時,必須使用BEGIN...END抱住函數體,存儲過程中BEGIN...END是可選的
- 創建用戶自定以的標量函數的Guidelines:
- 函數使用兩部分命名法,函數中引用的數據庫對象也使用兩部分命名法
- 在函數中,錯誤將導致整個函數停止執行,而存儲過程或者觸發器則是只取消產生錯誤的語句執行,然后繼續執行接下來的語句
- 函數修改底層數據庫被認為是有副作用的,在SQL Server中函數不允許有副作用,即不允許修改底層數據庫,因此你可能無法修改數據庫中的數據,無法執行存儲過程,無法執行動態SQL(能不能執行主要看是否修改了底層數據庫)
- 函數分為Deterministic,即在相同的數據庫狀態下提供同樣的輸入總是返回相同的值和Non-deterministic,即返回不同的值,可以使用OBJECTPROPERTY()函數確定函數是不是deterministic的
- 表值函數通常和參數化視圖是等價的,但是視圖是不允許傳遞用戶自定義的參數的;對於內聯函數來說,不用將函數體包含在BEGIN...END語句塊中,返回類型為TABLE,返回的表結構從SELECT語句進行推導
- 多語句表值函數允許更加復雜的返回表構建邏輯,函數體必須包含在BEGIN...END語句中,必須提供返回表的定義
- 視圖代碼直接納入到查詢代碼中(也就是將定義視圖的代碼和查詢代碼組合成一個查詢的代碼,而不是先執行視圖查詢,再對返回數據執行查詢),而標量函數則不是這樣的;在SELECT列表和WHERE語句中使用標量函數將帶來嚴重的性能問題
- 內聯表值函數將直接將代碼納入使用他們的查詢中,而多語句表值函數則不會這么做,除非多語句表值函數在查詢中只執行一次,否則其性能會很差;CROSS APPLY操作符用來為左邊表中每一行執行表值函數,這會帶來嚴重的性能問題,盡量避免
- 上述兩點中指出的性能問題,都是逐行調用了自定義函數,這樣需要為每行去提取自定義函數的定義,然后去執行這些定義,導致了性能問題;更深層次的原因是因為函數采用了過程式的處理方法,而SQL Server查詢數據則是基於數據集合的,這樣在采用過程式的逐行處理時,SQL Server性能就會顯著降低
- 創建函數的指導原則:
- 決定使用的函數類型
- 為每個任務創建一個函數,避免創建大函數,完成多任務的函數
- 使用兩部分命名法
- 考慮使用函數時的性能影響,通常來說,內聯函數比多語句函數性能要好
- 考慮和索引組合使用時的影響,對索引列使用函數很可能移除索引列的應用
- 避免引發錯誤,在函數中不允許錯誤處理
- 表值函數和存儲過程都能實現相似的結果,一些應用程序只能使用表值函數,另外一些只能使用存儲過程
- 函數
- 返回結果更容易訪問,存儲過程得使用輸出參數,使用起來更復雜
- 可以將表數據返回給一個變量
- 不能有數據相關的副作用,即不能修改數據,不能自行動態SQL語句
- 多語句表值函數通常有性能問題
- 存儲過程
- 可以修改數據
- 可以執行動態語句
- 可以包含詳細的異常處理
- 可以返回多結果集
- 表值函數和視圖通常都可以實現相似的結果
- 視圖
- 能夠被幾乎所有應用程序使用
- 和表非常相似
- 可以被更新
- 可以使用INSTEAD OF觸發器
- 表值函數
- 類似於參數化視圖
- 通常導致嚴重的性能問題(多語句表值函數)
- 不能納入到使用的查詢中
- 只有內聯表值函數可以更新