3

サブクエリにかっこを追加することで、アプリですぐに結果が返されました。

これは、vb.net / aspx Web アプリで RS2005 によって呼び出されると遅くなります。

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 @StartDate and @EndDate
    and c.schoolid = @SchoolID
    and std.GradeID=@GradeLevel
GROUP BY 
    c.TeacherID, sb.behaviorID, b.BehaviorName, u.lname, u.FName, 
    std.GradeID, gl.GradeLevel
ORDER BY 
    u.LName, sb.behaviorID

これは高速に実行されます:

select a.teacherid, a.teacher,a.bxcount, a.behaviorid,a.behaviorname,a.gradeid, a.gradelevel
from (
    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 @StartDate and @EndDate
        and c.schoolid = @SchoolID
        and std.GradeID=@GradeLevel
    group by c.TeacherID, sb.behaviorID, b.BehaviorName, u.lname, u.FName, std.GradeID, gl.GradeLevel
    ) a
    order by a.teacher, a.behaviorid

これらは、SQL Server Management Studio のクエリ ウィンドウで同じ速度で実行されます。違いはなぜですか?ありがとう。

4

1 に答える 1

7

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

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

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

したがって、2 つのクエリの構造が異なるため、Sql Server が 2 つの非常に異なる実行プランを作成しているという違いが見られます。

幸いなことに、解決策は非常に簡単です。パラメーターを内部変数に入れ、代わりにこれらをクエリで使用します。レポートでこれを行ったところ、Visual Studio で開発バージョンが行ったように、実稼働レポートが 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;
于 2013-06-05T00:56:46.293 に答える