我是一个非常初学的sql,我需要编写一个SP,以增加产品的视图数量。当用户在网站上搜索时,我们希望增加搜索返回的所有产品的计数器。我发现我的SP存在两个问题:
许多线程同时调用SP。实现之后,我遇到了很多超时异常。我的计数表看起来像这样:
ProductsViewsCount(ProductId int,Timestamp datetime,ViewType int,Count int)
Tiemstamp列四舍五入到调用SP的.net代码中最接近的小时。基本上我会按小时计算观点。
SP看起来像这样:
CREATE PROCEDURE [dbo].[IncrementProductsViews]
-- Add the parameters for the stored procedure here
@ProductsIds as varchar(max) = '', --CSV ids of products that were returned by search
@ViewType int,
@Timestamp datetime
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
DECLARE @id int
DECLARE idsCursor CURSOR FOR
SELECT Data FROM dbo.Split(@ProductsIds,',')
OPEN idsCursor
FETCH NEXT FROM idsCursor INTO @id
WHILE @@FETCH_STATUS = 0
BEGIN
BEGIN TRAN
UPDATE dbo.ProductsViewsCount SET Count = Count + 1
WHERE ProductId = @id AND ViewType = @ViewType AND Timestamp = @Timestamp
if @@rowcount = 0
BEGIN
INSERT INTO dbo.ProductsViewsCount (ProductId, Timestamp, ViewType, Count)
VALUES (@id, @Timestamp, @ViewType, 1)
END
COMMIT TRAN
FETCH NEXT FROM idsCursor INTO @id
END
CLOSE idsCursor
DEALLOCATE idsCursor
select 1
END
我能以更有效的方式做到这一点吗?
答案 0 :(得分:3)
您可以在设置操作而不是光标上执行此操作:
CREATE PROCEDURE [dbo].[IncrementProductsViews]
-- Add the parameters for the stored procedure here
@ProductsIds as varchar(max) = '', --CSV ids of products that were returned by search
@ViewType int,
@Timestamp datetime
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
;WITH CTE AS
(
SELECT *
FROM dbo.ProductsViewsCount
WHERE ViewType = @ViewType AND [Timestamp] = @Timestamp
)
MERGE CTE AS A
USING (SELECT * FROM dbo.Split(@ProductsIds,',')) B
ON A.ProductId = B.Data
WHEN MATCHED THEN UPDATE SET A.[Count] = B.[Count] + 1
WHEN NOT MATCHED BY TARGET THEN
INSERT(ProductId, [Timestamp], ViewType, [Count])
VALUES(Data, @Timestamp, @ViewType, 1);
SELECT 1 -- I don't know why this is here
END
答案 1 :(得分:1)
使用SQL Server 2008,您有一个不错的新选项(http://technet.microsoft.com/en-us/library/bb510625(SQL.100).aspx):
with ProductViewsCountSelect as (select * from ProductViewsCount where ViewType = @ViewType and [Timestamp] = @Timestamp)
merge into ProductViewsCountSelect
using (select data, count(*) as cnt from dbo.split('A,B,C,A', ',') group by data) d on ProductViewsCountSelect.ProductId = d.data
when matched
then update set ProductViewsCountSelect.Count = ProductViewsCountSelect.count + cnt
when not matched
then insert (ProductId, [TimeStamp], ViewType, [Count]) values( d.data, @TimeStamp, @ViewType, cnt);