Как убить долгую хранимую процедуру с помощью spid, когда другие вызовы этой хранимой процедуры используют тот же spid? - PullRequest
0 голосов
/ 05 августа 2020

У меня есть хранимая процедура, которая отображает продукты в категории - Распродажа, Мужская одежда и т. Д. c. Первое, что он делает, это проверяет таблицу, чтобы увидеть, обрабатывает ли уже spro c эту категорию. Таблица состоит из категории, статуса - «inProgress», например - время последнего выполнения и spid.

Если статус обрабатывается, он завершается. Если статус пуст, он обновляет таблицу статусов с соответствующей информацией: "inProgress", getdate () и spid.

Может быть 50 вызовов к этому spro c в любую минуту, и это не редкость, когда в каждую секунду выполняется 10 или 20 экземпляров spro c.

Проблема в том, что все экземпляры используют один и тот же spid. То, что я пытаюсь сделать вверху, - это проверить, является ли вызываемая категория c «обрабатываемой» и датой более 60 секунд. Обычно эта spro c запускается всего за 2-3 секунды, даже с тысячами продуктов. Итак, если выполнение продолжается более 60 секунд, я хочу убить этот конкретный экземпляр и запустить новый.

Вот код:

ALTER PROCEDURE [dbo].[KP_ViewCategories]
    -- Add the parameters for the stored procedure here
    @pIdCategory int
    ,@pFolder varchar(20)
    ,@pArrayExists varchar(5) = 'false'
    ,@pPageCheckSum varchar(32)=''
    ,@pStaleRecordSeconds int=900
    ,@pCountry varchar(2)='US'
AS
BEGIN
    SET NOCOUNT ON;
    SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
    declare @idCategory int =@pIdCategory
    declare @folder varchar(20)=@pFolder
    declare @arrayExists varchar(5)=Lower(@pArrayExists)
    declare @pageChecksum varchar(32)=@pPageCheckSum
    declare @staleRecordSeconds int=cast(@pStaleRecordSeconds as int)
    declare @country varchar(2)=@pCountry
    declare @curCheckSum varchar(32)
    declare @catTimestamp datetime
    declare @curTime datetime=getdate()
    declare @arrayStatus varchar(10)
    declare @newArrivalString varchar(15)=case when @country='US' then 'New Arrivals/%' else '%/New Arrivals' end
    declare @spid int =@@spid
    declare @catspid int

    select @curCheckSum=CatCheckSum, @catTimeStamp=CatTimestamp, @arrayStatus=arrayStatus, @catspid=spid from kp_grandArray where FolderName=@folder and idCategory=@idCategory
    IF (@curCheckSum is null or @catTimeStamp is null or DATEDIFF(ss,@catTimeStamp,@curTime)>@staleRecordSeconds or @arrayExists='clear')  and( @arrayStatus<>'inProgress' or @arrayStatus is null or DATEDIFF(ss,@catTimeStamp,@curTime)>@staleRecordSeconds+20) --or 1=1
    BEGIN -- our data is stale and a client is requesting data
        IF  @arrayStatus='inProgress'
        BEGIN
            kill -1000 -- REALLY, kill the bad spid
        END
        Merge KP_GrandArray t
            using (SELECT @idCategory as idCategory, @folder as folder) s
            on t.FolderName=s.folder and t.idcategory=s.idCategory
            when matched then update set arrayStatus='inProgess',CatTimeStamp=getDate(),CatChecksum='',spid=@spid
            when not matched then insert (FolderName,idCategory,CatTimestamp,CatChecksum,arrayStatus,spid) values (s.folder, s.idCategory,getdate(),'','inProgress',@spid);
        BEGIN TRY
        ;with 
        allProds as (
        SELECT distinct 
            AllProds.idProduct
            , AllProds.sku
            , AllProds.description
            , cast(AllProds.price as decimal(8,2)) as price
            , cast(AllProds.listprice as decimal(8,2)) as listPrice
            , AllProds.listHidden
            , AllProds.smallImageUrl
            , AllProds.stock
            , AllProds.noStock
            , AllProds.pcprod_HideBTOPrice
            , AllProds.FormQuantity NotForSale
            , cast(AllProds.sDesc as varchar(8000)) sDesc
            , AllProds.sales
            , (select ','+replace(replace(isnull((SELECT cast(options.idoption as varchar)+',' AS X  FROM options_optionsGroups INNER JOIN options ON options_optionsGroups.idOption = options.idOption  WHERE options_optionsGroups.idOptionGroup = 8 AND options_optionsGroups.idProduct = allProds.idProduct AND options.idoption IN (SELECT OOG2.idOption FROM products P2 INNER JOIN options_optionsGroups OOG2 ON P2.pcprod_ParentPrd = OOG2.idProduct WHERE CHARINDEX(CAST(OOG2.idoptoptgrp AS VARCHAR), '_' + P2.pcprod_Relationship) > 0 AND P2.stock > 0 AND P2.pcProd_SPInActive = 0 AND P2.pcprod_ParentPrd = allProds.idProduct)  ORDER BY options_optionsGroups.sortOrder, options.optiondescrip FOR XML PATH('')),0),'<X>',''),'</X>','')) AS sizeIDs    
            --, (SELECT CASE WHEN EXISTS (SELECT * FROM categories C INNER JOIN categories_products CP ON C.idCategory = CP.idCategory WHERE C.idCategory = (SELECT TOP 1 C2.idcategory FROM categories C2 WHERE C2.pcCats_MetaKeywords LIKE 'New Arrivals/%' ORDER BY C2.idCategory DESC) AND CP.idProduct = AllProds.idProduct ) THEN CAST(1 AS BIT) ELSE CAST (0 AS BIT) END) AS isNewArrival 
            , (SELECT CASE WHEN EXISTS (SELECT * FROM categories C INNER JOIN categories_products CP ON C.idCategory = CP.idCategory WHERE C.idCategory = (SELECT TOP 1 C2.idcategory FROM categories C2 WHERE C2.pcCats_MetaKeywords LIKE @newArrivalString ORDER BY C2.idCategory DESC) AND CP.idProduct = AllProds.idProduct ) THEN CAST(1 AS BIT) ELSE CAST (0 AS BIT) END) AS isNewArrival 
            , 0 AS collectionIDs 
            ,(select replace(replace((select cast(cp.idCategory as varchar) + ',' as X from categories_products cp  join categories c on cp.idCategory=c.idCategory join categories parC on c.idParentCategory=parC.idCategory  where cp.idProduct=allProds.idproduct and parC.categoryDesc='shop by collection'    FOR XML PATH('')),'<X>',''),'</X>','')) as collectionArray 
            , ISNULL((SELECT TOP 1 CASE WHEN (LEN(C.pcCats_MetaKeywords) > 0) THEN C.priority ELSE 0 END AS seasonalPriority FROM products P INNER JOIN categories_products CP ON P.idProduct = CP.idProduct INNER JOIN categories C ON CP.idCategory = C.idCategory WHERE p.idProduct = AllProds.idProduct AND C.idParentCategory = 38 ORDER BY seasonalPriority DESC),0) AS priority 
            , ISNULL((SELECT SUM(PO.quantity) FROM ProductsOrdered PO INNER JOIN products P ON PO.idProduct = P.idProduct INNER JOIN orders O ON PO.idOrder = O.idOrder WHERE O.orderDate >= DATEADD(day,-7,GETDATE()) AND P.pcprod_ParentPrd = AllProds.idProduct),0) AS recentSales 
            , idBrand gender
            ,selectedProducts.minPrice minPrice
            ,selectedProducts.maxPrice maxPrice
            ,selectedProducts.minListPrice minListPrice
            ,selectedProducts.maxListPrice maxListPrice
            , AllProds.rootSKU 
            , (select top 1 baseProduct+','+printdescription+','+stylecode from vwKP_productsByStyleCode where sku=AllProds.sku) styleInfo 
            , UPPER((select ','+ replace(replace(isnull((   SELECT c.categorydesc+'_'+cast(c.tier as varchar(1))+'_'+cast(c.idParentCategory as varchar(10))+',' AS X from categories_products cp INNER JOIN categories C ON CP.idCategory = C.idCategory   WHERE c.tier>1 and  C.idCategory NOT IN (SELECT idCategory FROM categories WHERE  idParentCategory IN (SELECT idCategory FROM categories WHERE categoryDesc = 'Shop by Collection'  or categoryDesc='Seasonal' or categoryDesc like '%sale%' or categoryDesc like '%featured%' or categoryDesc like '%gift%' or categoryDesc like 'kickee%'))  AND CP.idProduct = allProds.idproduct and C.iBTOhide = 0  ORDER BY C.priority ASC        FOR XML PATH('')),0),'<X>',''),'</X>','')+'||['+replace(replace(isnull((SELECT cast(cp.idCategory as varchar)+',' AS X from categories_products cp INNER JOIN categories C ON CP.idCategory = C.idCategory WHERE c.tier>1 and C.idCategory NOT IN (SELECT idCategory FROM categories WHERE idCategory IN (SELECT idCategory FROM categories WHERE categoryDesc = 'Shop by Collection'  or categoryDesc='Seasonal'   or categoryDesc like '%sale%' or categoryDesc like '%featured%' or categoryDesc like '%gift%' or categoryDesc like 'kickee%'))  AND CP.idProduct = allProds.idproduct and C.iBTOhide = 0 ORDER BY C.priority ASC FOR XML PATH('')),0),'<X>',''),'</X>','')+']')) styleArray     
            , (SELECT format(max(orderDate),'yyyyMMdd') FROM ProductsOrdered PO INNER JOIN products P ON PO.idProduct = P.idProduct INNER JOIN orders O ON PO.idOrder = O.idOrder WHERE P.pcprod_ParentPrd = AllProds.idProduct) AS lastOrderDate 
            , (select replace(replace(isnull((SELECT cast(cp.idCategory as varchar)+',' AS X FROM categories_products cp where idProduct=AllProds.idProduct     FOR XML PATH('')),0),'<X>',''),'</X>','')) as categoryArray
            , cast(BToBPrice as decimal(8,2)) wholeSalePrice 
            , '' as priceDesc
            , 0 as unavailable
            , selectedProducts.POrder
            , selectedProducts.active
        FROM KP_tvfValidProductsByCategory(@idcategory,@arrayExists) selectedProducts
        join products  allProds on selectedProducts.idProduct=allProds.idProduct
        ), -- END allProds
        jtemp as (
            select (select allProds.*
                ,q1.QoH QoH
                , case when q1.QoH<1 then 0 else 1 end as inStock
                , case when charindex('Boys',g1.genderArray)>0 or charindex('Girls',g1.genderArray)>0 then 'Kids,'+g1.genderArray else g1.genderArray end as genderArray
                from AllProds
                cross apply (
                    select replace(replace(isnull((SELECT categorydesc+',' AS X from categories_products cp join categories c on cp.idCategory=c.idCategory where cp.idProduct=allProds.idProduct and  charindex(','+categoryDesc,',Girls,Boys,Babies,Women,Men,Pets,Bedding,Socks')>0 FOR XML PATH('')),0),'<X>',''),'</X>','')+'||['+replace(replace(isnull((SELECT cast(cp.idCategory as varchar)+',' AS X from categories_products cp join categories c on cp.idCategory=c.idCategory where cp.idProduct=allProds.idProduct and charindex(','+categoryDesc,',Girls,Boys,Babies,Women,Men,Pets,Bedding,Socks')>0 FOR XML PATH('')),0),'<X>',''),'</X>','')+']' as genderArray        ) g1    
                cross apply (
                    SELECT sum(case when p.nostock=-1 then 1 when p.pcprod_Apparel=0 then p.stock else sp.stock end) QoH FROM products P left outer join products sp on p.idproduct=sp.pcprod_parentprd WHERE P.removed = 0 AND P.pcProd_SPInActive = 0 AND P.pcprod_ParentPrd = AllProds.idProduct 
                ) q1
                ORDER BY AllProds.SKU Asc for JSON PATH, root('products')) jOutput
        ), 
        jsonOut as (
            select * , CONVERT(NVARCHAR(32),HashBytes('MD5', jtemp.jOutput),2) newChecksum  from jtemp
        )
            --Merge KP_GrandArray t
            --using (select jsonout.*,@idCategory as idCategory, @folder as folder from jsonout) s
            --on t.FolderName=s.folder and t.idcategory=s.idCategory
            --when matched then update set t.[JSON]=s.jOutput,t.CatTimestamp=getdate(),t.CatChecksum=s.newChecksum,arrayStatus='',spid=@spid
            --when not matched then insert (FolderName,[JSON],idCategory,CatTimestamp,CatChecksum,arrayStatus,spid) values (s.folder, s.jOutput, s.idCategory,getdate(),s.newChecksum,'',@spid);
            --update KP_GrandArray set arrayStatus='' where folderName=@folder and idcategory=@idCategory
            update KP_GrandArray 
                set [JSON]=jsonOut.jOutput
                ,CatTimestamp=getdate()
                ,CatChecksum=jsonOut.newChecksum
                ,arrayStatus=''
                ,spid=@spid 
            from jsonOut
            where folderName=@folder and idcategory=@idCategory 
            --select * from jsonOut
        --now, send the new JSON back unless the checksum hasn't change, in which case an empty recordset is returned
            select [JSON] as jOutput, CatCheckSum from  kp_grandArray where FolderName=@folder and idCategory=@idCategory and (CatCheckSum<>@pageChecksum or @arrayExists='clear' or @arrayExists='false')
        END TRY
        BEGIN CATCH
            update KP_GrandArray set arrayStatus='', spid=@spid where folderName=@folder and idcategory=@idCategory
            select [JSON] as jOutput, CatCheckSum from  kp_grandArray where FolderName=@folder and idCategory=@idCategory
        END CATCH

    END -- IF WE NEED TO GET NEW DATA
    ELSE IF @arrayExists='false' or @arrayExists='clear' --the data does not need to be refreshed but we still need to return valid data
    BEGIN
        select [JSON] as jOutput, CatCheckSum from  kp_grandArray where FolderName=@folder and idCategory=@idCategory
    END
    ELSE BEGIN -- the data didn't need refreshing and the client already has valid data so just return an empty recordset
        select '' as jOutput, '' as CatChecksum where 1=2
    END
    SET TRANSACTION ISOLATION LEVEL READ COMMITTED;
END -- end sproc
...