3

With the addition of parens in the subquery, results were returned immediately in the app.

This runs slow when called by RS2005 in a vb.net / aspx web app:

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

This runs fast:

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

These run at the same speed in a query windows in SQL Server Management Studio. Why the difference? Thanks.

4

1 回答 1

7

您可能遇到过参数嗅探存在问题的查询,这与 Sql Server 如何尝试优化您的查询执行计划有关,但在涉及 Reporting Services 的情况下,它会完全搞砸并使其运行缓慢。

我有一个报告案例,其中有两个复杂的查询,每个查询大约 150 行,但在我的开发环境中运行了 7 秒——整个报告不到 10 秒。但是,当部署到生产 SSRS 服务器时,报告花费了 7 多分钟,并且经常超时,导致报告无法运行。

有关此问题的大多数信息都与存储过程有关。不要因为你没有使用存储过程而忽略这一点(就像我长期以来所做的那样);它也与直接的 Sql 查询非常相关。

因此,您看到的不同之处在于 Sql Server 创建了两个非常不同的执行计划,因为这两个查询的结构不同。

幸运的是,解决方案非常简单:将参数放入内部变量中,然后在查询中使用它们。我用我的报告做了这个,生产报告回到了 10 秒,就像 Visual Studio 中的开发版本一样。

要绕过第一个查询的参数嗅探,您可以使它看起来像这样:

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 回答