首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 數據庫知識 >  >> SQL Server 資料庫 >> 關於SqlServer

SQL Server 視圖中使用 NEWID()、GETDATE() 等非確定性函數的繞過技巧

     編輯:關於SqlServer

限制根因

SQL Server 規定視圖定義中不得直接引用非確定性函數(NEWID()、GETDATE()、RAND()、NEWSEQUENTIALID() 等),否則創建視圖報錯:無法在視圖中使用非確定性函數。原因在於視圖展開時需保證確定性,便於查詢優化器推理等價變換。

經典繞過模式:內聯表值函數 (iTVF) 包裝

CREATE FUNCTION dbo.GetNewId()
RETURNS TABLE
WITH SCHEMABINDING
AS
RETURN SELECT NEWID() AS RandVal;
GO

CREATE VIEW vw_RandomNumbers
AS
SELECT 1 AS PIndex, f.RandVal FROM dbo.GetNewId() f
UNION ALL SELECT 2, f.RandVal FROM dbo.GetNewId() f
UNION ALL SELECT 3, f.RandVal FROM dbo.GetNewId() f
UNION ALL SELECT 4, f.RandVal FROM dbo.GetNewId() f;
GO

原理:iTVF 內部允許非確定性函數,視圖僅引用確定性的 iTVF,滿足編譯檢查;運行時 iTVF 內聯展開,每行獨立求值,產生不同 GUID。

替代方案對比

方案優點缺點適用場景
iTVF 包裝語義清晰、可復用、執行計劃內聯需創建函數對象、跨庫需三部分命名常用隨機列、審計列、測試數據生成
存儲過程 + 游標/循環邏輯靈活、可控事務性能差、難併發、不返回結果集直連複雜業務流程、批量異構寫入
應用層生成零資料庫負擔、類型安全需修改應用代碼、分布式事務複雜新開發項目、微服務架構
CHECKSUM(NEWID()) 取模無需額外對象、單語句視圖中仍報錯,需配合 CTE/子查詢臨時腳本、一次性報表

進階用法:視圖中產生穩定偽隨機序列

若需同一查詢內每行不同、但跨查詢可重現(如分頁抽樣),可引入確定性種子:

CREATE VIEW vw_SampleRows
AS
SELECT TOP (100) PERCENT
    t.ID,
    CHECKSUM(t.ID, @@DBTS) % 1000 AS DeterministicRand
FROM dbo.BigTable t
ORDER BY DeterministicRand;

利用 @@DBTS(數據庫時間戳)作為查詢級種子,配合主鍵 ID 計算校驗和,滿足視圖確定性要求,又能產生均勻分布偽隨機數。

最佳實踐建議

  1. 優先採用 iTVF + SCHEMABINDING,獲得內聯性能與元數據保護雙重收益。
  2. 避免在高頻 OLTP 視圖中引入非確定性邏輯,導致計劃緩存失效、參數嗅探失誤。
  3. 測試數據生成、報表抽樣等低頻場景,直接在應用層或 ETL 階段處理隨機性,保持數據庫純關係特性。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved