sql >> Database >  >> RDS >> Sqlserver

Waarom wordt de 2e T-SQL-query veel sneller uitgevoerd dan de eerste wanneer deze wordt aangeroepen door Reporting Services 2005 in een web-app

Mogelijk bent u een query tegengekomen die een probleem heeft met het snuiven van parameters, wat te maken heeft met hoe Sql Server uw plan voor het uitvoeren van query's probeert te optimaliseren, maar in gevallen waarin Reporting Services erbij betrokken is, verknoeit het volledig en laat het ongelooflijk langzaam werken.

Ik had een casus met een rapport met twee complexe queries van elk ongeveer 150 regels, maar dat in mijn ontwikkelomgeving in 7 seconden liep - het hele rapport duurde minder dan 10 seconden. Bij implementatie op de SSRS-productieserver duurde het rapport echter meer dan 7 minuten en trad er vaak een time-out op, waardoor het rapport onuitvoerbaar werd.

De meeste informatie over dit probleem gaat erover in relatie tot opgeslagen procedures. Negeer dit niet omdat u geen opgeslagen procedures gebruikt (zoals ik lange tijd deed); het is ook zeer relevant voor rechte SQL-query's.

Dus het verschil dat u ziet, is dat Sql Server twee zeer verschillende uitvoeringsplannen maakt, omdat de twee query's anders zijn gestructureerd.

Gelukkig is de oplossing heel eenvoudig:plaats de parameters in interne variabelen en gebruik deze in plaats daarvan in uw query. Ik deed dit met mijn rapport en het productierapport ging terug naar 10 seconden zoals de ontwikkelingsversie deed in Visual Studio.

Als u het snuiven van parameters voor uw eerste zoekopdracht wilt omzeilen, ziet u deze er als volgt uit:

BEGIN
    -- Use internal variables to solve parameter sniffing issues
    DECLARE @StartDateInternal AS DATETIME;
    DECLARE @EndDateInternal AS DATETIME;
    DECLARE @SchoolIDInternal AS INT;
    DECLARE @GradeLevelInternal AS INT;

    -- Copy the parameters into the internal variables
    SET @StartDateInternal = @StartDate;
    SET @EndDateInternal = @EndDate;
    SET @SchoolIDInternal = @SchoolID;
    SET @GradeLevelInternal = @GradeLevel;

    -- Now use the internal variables in your query rather than the parameters
    SELECT 
        c.TeacherID, u.FName + ' ' + u.lname as Teacher, count(sb.behaviorID) as BxCount, 
        sb.behaviorID, b.BehaviorName, std.GradeID, gl.GradeLevel
    FROM 
        StudentBehaviors sb
    join 
        Classes c on sb.classid = c.classid
    join 
        StudentDetails std on sb.studentID = std.StudentID and std.RecordIsActive=1
    join 
        users u on c.TeacherID = u.UserID
    join 
        Behaviors b on sb.behaviorID = b.BehaviorID
    join 
        GradeLevels gl on std.GradeID = gl.GradeLevelID
    WHERE 
        sb.classdate between @StartDateInternal and @EndDateInternal
        and c.schoolid = @SchoolIDInternal
        and std.GradeID = @GradeLevelInternal
    GROUP BY 
        c.TeacherID, sb.behaviorID, b.BehaviorName, u.lname, u.FName, 
        std.GradeID, gl.GradeLevel
    ORDER BY 
        u.LName, sb.behaviorID;

END;



  1. MySQL:LAAD GEGEVENS LOKAAL INFILE inschakelen

  2. Hoe repareer ik een InnoDB-tabel?

  3. In wachtrij plaatsen in OneWay WCF-berichten met Windows Service en SQL Server

  4. Officiële Microsoft Access Tech Blog is nu online!