sql >> データベース >  >> RDS >> Sqlserver

WebアプリでReportingServices2005によって呼び出されたときに、2番目のT-SQLクエリが最初のクエリよりもはるかに高速に実行されるのはなぜですか

    パラメータスニッフィングに問題があるクエリに遭遇した可能性があります。これは、SQL Serverがクエリ実行プランを最適化しようとする方法に関係していますが、Reporting Servicesが関与している場合は、クエリが完全に台無しになり、実行が非常に遅くなります。

    それぞれ約150行の2つの複雑なクエリが含まれているが、開発環境では7秒で実行されたレポートのケースがありました。レポート全体の所要時間は10秒未満でした。ただし、本番SSRSサーバーにデプロイすると、レポートに7分以上かかり、タイムアウトしてレポートを実行できなくなることがよくありました。

    この問題に関するほとんどの情報は、ストアドプロシージャに関連して問題について説明しています。ストアドプロシージャを使用していないため、これを却下しないでください(私が長い間使用していたように)。ストレートSQLクエリにも非常に関連しています。

    したがって、表示されている違いは、2つのクエリの構造が異なるため、SQLServerが2つの非常に異なる実行プランを作成していることです。

    幸い、解決策は非常に単純です。パラメーターを内部変数に入れ、代わりにこれらをクエリで使用します。私は自分のレポートでこれを行い、本番レポートはVisualStudioの開発バージョンと同じように10秒に戻りました。

    最初のクエリのパラメータスニッフィングをバイパスするには、次のようにします。

    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. PDOプリペアドステートメントから生のSQLクエリ文字列を取得する

    2. 別のアプリケーションから1つのアプリケーションのデータベースにアクセスする

    3. 最初にEFコードを使用して複合キーをマッピングする

    4. 文字列を異なる列に分割する方法は?