I am a very beginner with sql and I need to write a SP in order to increment products views count. When user searches on site we want to increment the counter for all products that were returned by search. I see two problems with my SP:
- it uses cursor
- it starts a lot of transactions
The SP is called simultaneous by many threads. After I implemented it I got many timeout exceptions. My count table looks like this:
ProductsViewsCount(ProductId int, Timestamp datetime, ViewType int, Count int)
Tiemstamp column is rounded to the closest hour in .net code that calls the SP. Basically I will count the views by hour.
The SP looks like this:
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
Can I do this in a more efficient manner?
You can do it on a set operation instead of a cursor: