1

私はSQLの初心者であり、製品のビュー数を増やすためにSPを作成する必要があります。ユーザーがサイトで検索するとき、検索によって返されたすべての製品のカウンターをインクリメントしたいと思います。SPに2つの問題があります。

  1. カーソルを使用します
  2. それは多くのトランザクションを開始します

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

これをより効率的な方法で行うことはできますか?

4

2 に答える 2

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
于 2012-06-08T20:00:50.210 に答える
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);
于 2012-06-08T20:29:29.297 に答える