CREATEORALTER PROC [dbo].[CalculateStake] @CategoryIDint, @ProductIDsmallint , @ProdcutGroupIDsmallint, @PriceLimit [uftt_PriceLimit] readonly AS BEGIN SET NOCOUNT ON;
MERGEINTO [dbo].[PriceLimitation] t1 USING@PriceLimit t2 ON t1.UserID = t2.UserID AND t1.ProdcutGroupID=@ProdcutGroupID AND t1.CategoryID=@CategoryID AND t1.ProductID =@ProductID WHEN MATCHED THEN UPDATESET t1.StakeAmount = t1.StakeAmount + t2.StakeAmount WHENNOT MATCHED THEN INSERTVALUES(@CategoryID, @ProdcutGroupID, t2.UserID ,t2.StakeAmount, @ProductID); END
主要傳入參數判斷更新或新增[dbo].[PriceLimitation]表
我們在ELK發現在執行SP時很少概率會發生PRIMARY KEY重複問題.
Violation of PRIMARY KEY constraint ‘PK_PriceLimitation’. Cannot insert duplicate key in object ‘dbo.PriceLimitation’.
;with cte as( select@fromas num unionall select num +1as num from cte where num <@from+500 ) insert into@PriceLimit ([UserID],[StakeAmount],CategoryID,[ProductID],[ProdcutGroupID]) select num,100,@CategoryID,@ProductID,@ProdcutGroupID from cte option(MAXRECURSION 0);
請務必只從目標資料表指定用於比對用途的資料行。 也就是說,從目標資料表中指定要與來源資料表的對應資料行進行比較的資料行。 請勿嘗試在 ON 子句中篩選出目標資料表的資料列 (例如指定 AND NOT target_table.column_x = value) 來改善查詢效能。 這樣做可能會傳回非預期且不正確的結果。
CREATEORALTER PROC [dbo].[CalculateStake] @CategoryIDint, @ProductIDsmallint , @ProdcutGroupIDsmallint, @PriceLimit [uftt_PriceLimit] readonly AS BEGIN SET NOCOUNT ON;
MERGEINTO [dbo].[PriceLimitation] t1 USING@PriceLimit t2 ON t1.UserID = t2.UserID WHEN MATCHED AND t1.ProdcutGroupID=@ProdcutGroupID AND t1.CategoryID=@CategoryID AND t1.ProductID =@ProductID THEN UPDATESET t1.StakeAmount = t1.StakeAmount + t2.StakeAmount WHENNOT MATCHED THEN INSERTVALUES(@CategoryID, @ProdcutGroupID, t2.UserID ,t2.StakeAmount, @ProductID); END
新寫法的執行計畫在對於大資料表時會很沒效率….
改寫後遇到的問題(不好的執行計畫)
一般SP在執行過後都會把使用的執行計畫快取起來,所以我們可以透過DMV來查看執行執行計畫.
1 2 3 4 5
SELECT Cacheobjtype, Objtype, TEXT, query_plan FROM sys.dm_exec_cached_plans t1 CROSS APPLY sys.dm_exec_sql_text(plan_handle) t2 CROSS APPLY sys.dm_exec_query_plan(plan_handle) t3 where t2.objectid = object_id('dbo.CalculateStake', 'p')
drop proc[dbo].[CalculateStake] drop type [dbo].[uftt_PriceLimit]
CREATE TYPE [dbo].[uftt_PriceLimit] ASTABLE( [CategoryID] [int] NOT NULL, [ProdcutGroupID] [smallint] NOT NULL, [UserID] [int] NOT NULL, [StakeAmount] [numeric](18, 4) NOT NULL, [ProductID] [smallint] NOT NULL, PRIMARY KEY CLUSTERED ( [UserID] ASC, [CategoryID] ASC, [ProductID] ASC, [ProdcutGroupID] ASC )WITH (IGNORE_DUP_KEY = OFF) )
GO
CREATEORALTER PROC [dbo].[CalculateStake] @PriceLimit [uftt_PriceLimit] readonly AS BEGIN SET NOCOUNT ON;
MERGEINTO [dbo].[PriceLimitation] t1 USING@PriceLimit t2 ON t1.UserID = t2.UserID AND t1.ProdcutGroupID= t2.ProdcutGroupID AND t1.CategoryID=t2.CategoryID AND t1.ProductID =t2.ProductID WHEN MATCHED THEN UPDATESET t1.StakeAmount = t1.StakeAmount + t2.StakeAmount WHENNOT MATCHED THEN INSERTVALUES(t2.CategoryID, t2.ProdcutGroupID, t2.UserID ,t2.StakeAmount, t2.ProductID); END
;with cte as( select@fromas num unionall select num +1as num from cte where num <@from+500 ) insert into@PriceLimit ([UserID],[StakeAmount],CategoryID,[ProductID],[ProdcutGroupID]) select num,100,@CategoryID,@ProductID,@ProdcutGroupID from cte option(MAXRECURSION 0);