Sqlserver
 sql >> Baza danych >  >> RDS >> Sqlserver

Dlaczego drugie zapytanie T-SQL działa znacznie szybciej niż pierwsze wywołane przez Reporting Services 2005 w aplikacji internetowej?

Być może natknąłeś się na zapytanie, które ma problem z podsłuchiwaniem parametrów, co ma związek ze sposobem, w jaki Sql Server próbuje zoptymalizować plan wykonywania zapytań, ale w przypadkach, gdy zaangażowane są usługi Reporting Services, całkowicie je psuje i sprawia, że ​​działa ono niezwykle wolno.

Miałem przypadek z raportem, który zawierał dwa złożone zapytania po około 150 linii każde, ale które działały w ciągu 7 sekund w moim środowisku programistycznym - cały raport zajął mniej niż 10 sekund. Jednak po wdrożeniu na produkcyjnym serwerze SSRS raport zajmował ponad 7 minut i często przekraczał limit czasu, przez co nie można było uruchomić raportu.

Większość informacji o tym problemie mówi o tym w odniesieniu do procedur składowanych. Nie odrzucaj tego, ponieważ nie używasz procedur przechowywanych (tak jak ja przez długi czas); jest to również bardzo istotne w przypadku prostych zapytań SQL.

Różnica, którą widzisz, polega na tym, że SQL Server tworzy dwa bardzo różne plany wykonania, ponieważ te dwa zapytania mają inną strukturę.

Na szczęście rozwiązanie jest bardzo proste:umieść parametry w zmiennych wewnętrznych i użyj ich w zapytaniu. Zrobiłem to z moim raportem, a raport produkcyjny cofnął się do 10 sekund, tak jak wersja rozwojowa zrobiła w Visual Studio.

Aby ominąć wąchanie parametrów dla pierwszego zapytania, możesz sprawić, by wyglądało to tak:

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. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Skrypt do zabijania wszystkich połączeń z bazą danych (więcej niż RESTRICTED_USER ROLLBACK)

  2. Procesory AMD EPYC z serii 7002 i serwer SQL

  3. Nie można połączyć się z serwerem — błąd związany z siecią lub specyficzny dla instancji

  4. CEILING() Przykłady w SQL Server

  5. Zwróć wartość przyrostu kolumny tożsamości w SQL Server