Хранимая процедура продолжает работать - код отлично работает вне хранимой процедуры - PullRequest
0 голосов
/ 14 января 2020

У меня есть запрос SQL, который отлично работает вне хранимой процедуры. Когда я запускаю ее через хранимую процедуру, она просто запускается и никогда не завершается и, кажется, вызывает блокировки. Я делаю что-то просто неправильно, например, пропускаю NO LOCK в запросе sql cmd, или если есть что-то очевидное, я не вижу, что объясняет, почему эта хранимая процедура выполняется так долго и вызывает блокировку?

CREATE PROCEDURE [USP_GET_INACTIVE_REPORTS_EMAIL]
-- Author: XXXXXXXXX
-- Version 1.4 - Ready for Production ( LOL ! ) 
AS
BEGIN
    set nocount on;
    declare @trancount int;
    set @trancount = @@trancount;

    begin try

        SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;

        if @trancount = 0
            begin transaction usp_get_inactive_reports_email;
        else
            save transaction usp_get_inactive_reports_email;

        -- Step 1 - Create Temp Tables to hold Reporting DataSet for Active Reports that have not been executed in the last 30 days
        IF OBJECT_ID('tempdb..##temp01') IS NOT NULL 
        BEGIN 
            DROP TABLE ##temp01
        END

        IF OBJECT_ID('tempdb..##temp02') IS NOT NULL 
        BEGIN 
            DROP TABLE ##temp02
        END

        -- Step 2 - Query the Report Server Catalog and Execution Log for answers . Active reports defined as not being hidden and having a description populated.

        ;WITH RankedReports AS
        (
            SELECT 
                ReportID,
                TimeStart,
                UserName, 
                RANK() OVER (PARTITION BY ReportID ORDER BY TimeStart DESC) AS iRank
            FROM 
                ReportServer.dbo.ExecutionLog t1
            JOIN 
                ReportServer.dbo.Catalog t2 ON t1.ReportID = t2.ItemID 
                                            AND t2.Type <> 1
        )
        SELECT DISTINCT     
            t1.UserName, t2.Name AS ReportName,
            TimeStart,
            SUBSTRING(t2.Path, 2, LEN(t2.Path) - LEN(t2.Name) - 1) AS Folder,
            t2.Type
        INTO ##temp01
        FROM RankedReports t1
        INNER JOIN ReportServer.dbo.Catalog t2 ON t1.ReportID = t2.ItemID
        WHERE t1.iRank = 1 
          AND t2.Type <> 1
          AND CAST(TimeStart AS DATE) > GETDATE() - 30
        ORDER BY t1.UserName, t2.Name;

        --- Select * from ##temp01 order by timestart


        SELECT 
            cast ( SUBSTRING(Path,2,LEN(Path)-LEN(Name)-1) as varchar(100)) AS ReportFolder
            ,Name AS ReportName
            ,CreationDate
            ,ModifiedDate
            ,Type,replace([Description],'~','/') as Description,Hidden
            INTO ##temp02
            FROM ReportServer.dbo.Catalog 
        WHERE Name NOT IN (SELECT ReportName FROM ##temp01) 
            AND Path <> '' 
            AND SUBSTRING(Path,2,LEN(Path)-LEN(Name)-1)<>''
            AND Description is not NULL 
            AND Type = 2 -- Means Report Type according to Mictosoft Docs for Report Server Schema
            AND cast (ModifiedDate as date )<Getdate() - 30
        OR (
              Hidden='0' --- Reports that we have shown as hidden ad soft deletes done in SSRS
              AND Name NOT IN (SELECT ReportName FROM ##temp01) 
                AND Path <> '' 
                AND SUBSTRING(Path,2,LEN(Path)-LEN(Name)-1)<>''
                AND Type = 2 -- Means Report Type according to Mictosoft Docs for Report Server Schema)
                AND cast (ModifiedDate as date )<Getdate() - 30
            )
            ORDER BY Path



    -- Step 3 - If the Query return no results then dont email. If it does email it to requestforchange@creditfix.co.uk


    declare @counter int
    ;with query as (

        SELECT ReportFolder
            ,ReportName
             ,CreationDate
            ,ModifiedDate
            ,Type,[Description],Hidden 
        FROM ##temp02 where Hidden=0 AND Description is not null 


            )
    select @counter = count(*) from query


    --- Step 4 - If the count of rows from Inactive Reports query >0 then Send the email about which reports to xxxxx

IF @counter > 0
BEGIN


--execute xp_cmdshell 'bcp "SELECT '' ReportFolder,ReportName,CreationDate,ModifiedDate,Type,Description FROM ##temp02 WHERE ReportFolder <>''''AND Description is not NULL AND Type = 2 AND Hidden=0 ORDER BY 4" queryout C:\xxxxx\BI_Active_Reports_not_used_in_Last_30_days.csv -c -t, -S xxxxxx -U xxxxx -P xxxxxxx'

declare @fileNameTXT varchar(200) = '\\xxxxxx\Active_Reports_not_used_in_Last_30_days.csv'

declare @sql_bcp varchar(1000) = 'sqlcmd -S xxxxx -d xxxxxx Rep -E -Q "set nocount on; PRINT ''Reportname'' + '','' + ''ReportFolder'' ;SELECT  ReportName,ReportFolder FROM ##temp02 where Hidden=0 AND Description is not null  " -o ' + @filenameTXT + ' -W -h -1 -s"," -w 1500'

--print @sql_bcp


execute xp_cmdshell @sql_bcp

--- Send Email Section to export query contents to a CSV Output File 

EXEC msdb.dbo.sp_send_dbmail 
    @profile_name = 'SMTP Server Mail',
    @recipients= 'xxxxxx',
    @subject = 'IT - Active Reports not used in the Last 30 days',
    @execute_query_database = 'ReportServer',
    @body = 'Greetings, <br><br>
    Please find attached Reports that have not been run in the last 30 days. 
    <br><br>
    Kind Regards 
    <br><br>
    xxxxxx Team',
    @body_format = 'HTML',
    @file_attachments= '\\xxxxx\Active_Reports_not_used_in_Last_30_days.csv'

    commit transaction usp_get_inactive_reports_email

END
ELSE
    BEGIN
    --RAISERROR('No rows exist, quit job', 16, 1);
    commit transaction usp_get_inactive_reports_email;
    --print 'commit'
    Return;
    END


commit transaction usp_get_inactive_reports_email;
    end try
    begin catch
        declare @error int, @message varchar(4000), @xstate int;
        select @error = ERROR_NUMBER(), @message = ERROR_MESSAGE(), @xstate = XACT_STATE();
        if @xstate = -1
            rollback;
        if @xstate = 1 and @trancount = 0
            rollback
        if @xstate = 1 and @trancount > 0
            rollback ;

        raiserror ('usp_get_inactive_reports_email: %d: %s', 16, 1, @error, @message) ;
        return;
    end catch   
end

Some diagnostics showing locks when running SP

1 Ответ

3 голосов
/ 14 января 2020

Глобальные временные таблицы видны из нескольких сеансов, но имеют блокировку, как и обычные таблицы. Таким образом, сессии не могут прочитать незафиксированные изменения друг друга. Это включает незафиксированный DDL, такой как CREATE TABLE или SELECT ... INTO.

То, что у вас есть, - это не обнаруживаемая тупиковая ситуация между сеансами, эквивалентная:

begin transaction
create table ##t(id int)
exec xp_cmdshell 'bcp "select * from ##t" queryout "c:\temp\foo.csv" -S "localhost" -T'

Ваш сеанс BCP не может считывать данные из таблицы и ожидает его создания зафиксировано, и хранимая процедура ожидает на BCP.

...