简体   繁体   English

如何优化此查询? 我正在使用SQL Server 2008

[英]How can i optimize this query? I am using sql server 2008

I have this SQL query which is valid but always times out. 我有此SQL查询,但有效,但总是超时。

CREATE PROCEDURE Sibm_getstudentdivisionattendancereport2 (
    @course_id     INT,
    --@Subject_Id int,                                        
    @academic_year INT,
    @division_id   INT,
    @semister_id   INT,
    @fromdate1 DATETIME,
    @todate1 DATETIME)
AS
  BEGIN
      DECLARE @fromdate VARCHAR(100)
      DECLARE @todate VARCHAR(100)

      SET @fromdate=CONVERT(VARCHAR(10), @fromdate1, 105)
      SET @todate=CONVERT(VARCHAR(10), @todate1, 105)

      CREATE TABLE #getstudentmarks
        (
           id                   INT NOT NULL,
           roll_no              VARCHAR(100),
           stud_id              INT,
           stud_name            VARCHAR(200),
           stud_last_name       VARCHAR(200),
           subject_name         VARCHAR(200),
           marks                INT,
           student_id           INT,
           division_id          INT,
           division             VARCHAR(50),
           attended             VARCHAR(12),
           exempted             VARCHAR(12),
           total_attendance     VARCHAR(12),
           attendancepercentage VARCHAR(30),
           subject_id           INT
        )

      CREATE TABLE #getstudentmarks1
        (
           id                   INT IDENTITY(1, 1) NOT NULL,
           roll_no              VARCHAR(100),
           stud_id              INT,
           stud_name            VARCHAR(200),
           stud_last_name       VARCHAR(200),
           subject_name         VARCHAR(200),
           marks                INT,
           student_id           INT,
           division_id          INT,
           division             VARCHAR(50),
           attended             VARCHAR(12),
           exempted             VARCHAR(12),
           total_attendance     VARCHAR(12),
           attendancepercentage VARCHAR(30),
           subject_id           INT
        )

      CREATE TABLE #divisionlist
        (
           division_id INT
        )

      CREATE TABLE #getstudent_attended
        (
           id         INT IDENTITY(1, 1) NOT NULL,
           student_id INT,
           exempted   VARCHAR(12),
           attended   VARCHAR(12)
        )

      DECLARE @Total_Lectures INT
      DECLARE @Student_Id INT
      DECLARE @TotalConductedLecture INT
      DECLARE @TotalExempted INT

      INSERT INTO #getstudentmarks1
                  (roll_no,
                   student_id,
                   stud_name,
                   stud_last_name)
      SELECT DISTINCT( SA.roll_no ),
                     SA.student_id AS id,
                     SR.first_name,
                     SR.last_name
      FROM   tblstudent_academic_record SA,
             tblstudent_record SR
      WHERE  SR.student_id = SA.student_id
             AND SR.student_id IN (SELECT SAR.student_id
                                   FROM   tblstudent_academic_record SAR
                 INNER JOIN tblcoursesemester_subject_student
                            CSS
                         ON SAR.student_id = CSS.student_id
                            AND SAR.current_record = 1
                            AND SAR.course_id = @course_id
                            AND
                 SAR.semister_id = @semister_id
                            AND
                 SAR.division_id = @division_id
                            AND
                 SAR.academic_year = @academic_year)

      CREATE TABLE #temp
        (
           id           INT,
           subject_name VARCHAR(100)
        )

      DECLARE @Master_Id INT

      SET @Master_Id = 0

      IF EXISTS(SELECT *
                FROM   tblcoursesemester_main
                WHERE  academic_year = @Academic_Year
                       AND course_id = @Course_Id
                       AND semester_id = @semister_id)
        BEGIN
            SET @Master_Id = (SELECT TOP 1 cs_id
                              FROM   tblcoursesemester_main
                              WHERE  academic_year = @Academic_Year
                                     AND course_id = @Course_Id
                                     AND semester_id = @semister_id)
        END

      INSERT INTO #temp
      SELECT id,
             subject_name
      FROM   tblsubject
      WHERE  id IN (SELECT subject_id
                    FROM   tblcoursesemester_subject
                    WHERE  is_archieve IS NULL
                           AND cs_id = @Master_Id)
             AND isarchive IS NULL
      ORDER  BY subject_name

      DECLARE @tempid INT
      DECLARE @sub VARCHAR(max)
      DECLARE c1 CURSOR FOR
        SELECT student_id
        FROM   #getstudentmarks1

      OPEN c1

      FETCH next FROM c1 INTO @Student_Id

      WHILE @@FETCH_STATUS = 0
        BEGIN
            DECLARE c2 CURSOR FOR
              SELECT id
              FROM   #temp

            OPEN c2

            FETCH next FROM c2 INTO @tempid

            WHILE @@FETCH_STATUS = 0
              BEGIN
                  UPDATE #getstudentmarks1
                  SET    subject_name = (SELECT subject_name
                                         FROM   #temp
                                         WHERE  id = @tempid),
                         subject_id = @tempid
                  WHERE  student_id = @Student_Id

                  FETCH next FROM c2 INTO @tempid
              END

            CLOSE c2

            DEALLOCATE c2

            FETCH next FROM c1 INTO @Student_Id
        END

      CLOSE c1

      DEALLOCATE c1

      --select * from #TEMP  
      --SET IDENTITY_INSERT #GetStudentMarks1 ON  
      INSERT INTO #getstudentmarks
                  (id,
                   roll_no,
                   stud_id,
                   stud_name,
                   stud_last_name,
                   subject_name,
                   marks,
                   student_id,
                   division_id,
                   division,
                   attended,
                   exempted,
                   total_attendance,
                   attendancepercentage,
                   subject_id)
      SELECT #getstudentmarks1.id,
             roll_no,
             stud_id,
             stud_name,
             stud_last_name,
             #temp.subject_name,
             marks,
             student_id,
             division_id,
             division,
             attended,
             exempted,
             total_attendance,
             attendancepercentage,
             #temp.id
      FROM   #getstudentmarks1
             CROSS JOIN #temp

      -- select * from #GetStudentMarks cross join #TEMP  
      --SET IDENTITY_INSERT #GetStudentMarks1 OFF  
      --select * from #GetStudentMarks  
      ---------calculate percentage-------------------        
      INSERT INTO #divisionlist
      SELECT divisionid
      FROM   tblschedulemaster
      WHERE  academicyear = @academic_year
             AND courseid = @Course_Id
             AND semesterid = @Semister_Id

      DECLARE @subject_id INT
      DECLARE c1 CURSOR FOR
        SELECT student_id
        FROM   #getstudentmarks

      OPEN c1

      FETCH next FROM c1 INTO @Student_Id

      WHILE @@FETCH_STATUS = 0
        BEGIN
            DECLARE c3 CURSOR FOR
              SELECT subject_id
              FROM   #getstudentmarks

            OPEN c3

            FETCH next FROM c3 INTO @subject_id

            WHILE @@FETCH_STATUS = 0
              BEGIN
                  --  GET TOTAL LECTURES OF EACH STUDENT                          
                  SELECT @Total_Lectures = Count([id])
                  FROM   tblfacultyschedule
                  WHERE  subjectid = @subject_id
                         AND sch_mas_id IN (SELECT [id]
                                            FROM   tblschedulemaster
                                            WHERE  academicyear = @academic_year
                                                   AND courseid = @Course_Id
                                                   AND semesterid = @Semister_Id
                                                   AND divisionid IN (
                                                                     -- Changed Divisions list Query Starts                  
                                                                     SELECT
                                                       divisionid
                                                                      FROM
                                                       tblschedulemaster
                                                                      WHERE
                                                       id IN (SELECT DISTINCT
                                                             sch_mas_id
                                                              FROM
                                                       tblfacultyschedule
                                                              WHERE
                                                       [date] >= @fromdate
                                                       AND [date] <= @todate
                                                       AND
                                           id IN (SELECT DISTINCT
                                                 schedule_id
                                                  FROM
                                           tblstudentattendence
                                                  WHERE
                                           student_id = @Student_Id
                                           AND schedule_id IN (SELECT
                                               id
                                                               FROM
                                               tblfacultyschedule
                                                               WHERE
                                               subjectid =
                                               @subject_id
                                               AND
                                                 sch_mas_id IN(SELECT
                                                 id
                                                               FROM
                                                 tblschedulemaster
                                                               WHERE
                                                 academicyear =
                                                 @academic_year
                                                 AND
                                                            courseid =
                                                            @Course_Id
                                                             AND
                                                            semesterid
                                                            =
                                                 @Semister_Id))
                                                 ))
                                                     -- Changed Divisions list Query Ends                  
                                                     ))
                         AND COALESCE(other_activity, '') NOT LIKE '%LUNCH%'

                  --print 'subject id'                                                   
                  --print @subject_id  
                  --print 'totol att'  
                  --print @Total_Lectures             
                  -- Total Conducted Lectures                            
                  SET @TotalConductedLecture =
                  (SELECT
                  COALESCE(Count(is_attended), 0) AS Attended
                                                FROM   tblstudentattendence
                                                WHERE  student_id = @Student_id
                                                       AND is_attended = 'YES'
                                                       AND
                  schedule_id IN (SELECT [id]
                                  FROM
                  tblfacultyschedule
                                  WHERE
                  [date] >= @fromdate
                  AND [date] <= @todate
                  AND subjectid = @subject_id
                  AND
                  sch_mas_id IN (SELECT [id]
                                 FROM
                  tblschedulemaster
                                 WHERE
                  academicyear = @academic_year
                  AND courseid = @course_id
                  AND semesterid = @semister_id
                  AND divisionid IN (SELECT
                      division_id
                                     FROM
                      #divisionlist))
                                                           AND
                  COALESCE(other_activity, '')
                  NOT
                  LIKE
                  '%LUNCH%'
                                                           AND
                  subjectid IN (SELECT DISTINCT
                               subject_id
                                FROM
                  tblcoursesemester_subject
                                WHERE
                  cs_subject_id IN (SELECT
                  cs_subject_id
                                    FROM
                  tblcoursesemester_subject_student
                                    WHERE
                  cs_subject_id IN (SELECT
                  cs_subject_id
                                    FROM
                  tblcoursesemester_subject
                                    WHERE
                  cs_id IN (SELECT cs_id
                            FROM
                  tblcoursesemester_main
                            WHERE
                  academic_year = @academic_year
                  AND course_id = @course_id
                  AND semester_id = @semister_id
                           )
                  AND is_archieve IS NULL)
                  AND student_id = @Student_id
                  AND is_archieve IS NULL)
                  AND is_archieve IS NULL)))
                  --print 'attended'        
                  -- print @TotalConductedLecture   
                  -- NOW COUNT Exempted LECTURES         
                  SET @TotalExempted=
                  (SELECT COALESCE(Count(is_attended), 0) AS
                          Attended
                   FROM   tblstudentattendence
                   WHERE  student_id = @Student_id
                          AND is_attended = 'EXEMPTED'
                          AND schedule_id IN (SELECT [id]
                                              FROM
                              tblfacultyschedule
                                              WHERE
                              [date] >= @fromdate
                              AND [date] <= @todate
                              AND subjectid =
                                  @subject_id
                              AND sch_mas_id IN (SELECT
                                  [id]
                                                 FROM
                                  tblschedulemaster
                                                 WHERE
                                  academicyear =
                                  @academic_year
                                  AND
                                             courseid =
                                             @course_id
                                              AND
                                             semesterid =
                                             @semister_id
                                                         AND
                                             divisionid IN (
                                             SELECT
                                             division_id
                                             FROM
                                             #divisionlist))
                                                     AND
                              COALESCE(other_activity, '') NOT
                              LIKE
                              '%LUNCH%'
                                                     AND
                                  subjectid IN (SELECT DISTINCT
                                               subject_id
                                                FROM
                                  tblcoursesemester_subject
                                                WHERE
                                  cs_subject_id IN (SELECT
                                  cs_subject_id
                                                    FROM
                                  tblcoursesemester_subject_student
                                                    WHERE
                                  cs_subject_id IN (SELECT
                                  cs_subject_id
                                                    FROM
                                  tblcoursesemester_subject
                                                    WHERE
                                  cs_id IN (SELECT cs_id
                                            FROM
                                  tblcoursesemester_main
                                            WHERE
                                  academic_year = @academic_year
                                  AND course_id = @course_id
                                  AND semester_id = @semister_id
                                           )
                                  AND is_archieve IS NULL)
                                  AND student_id = @Student_id
                                  AND is_archieve IS NULL)
                                  AND is_archieve IS NULL)))

                  -- print 'not attended'  
                  -- print @TotalExempted  
                  UPDATE #getstudentmarks
                  SET    #getstudentmarks.total_attendance = @Total_Lectures,
                         #getstudentmarks.attended = @TotalConductedLecture,
                         #getstudentmarks.exempted = @TotalExempted
                  WHERE  student_id = @Student_Id
                         AND subject_id = @subject_id

                  FETCH next FROM c3 INTO @subject_id
              END

            CLOSE c3

            DEALLOCATE c3

            FETCH next FROM c1 INTO @Student_Id
        END

      CLOSE c1

      DEALLOCATE c1

      -- CURSOR ENDS      
      --select * from #GetStudentMarks                   
      UPDATE #getstudentmarks
      SET    #getstudentmarks.division = tbldivision.division
      FROM   #getstudentmarks,
             tbldivision
      WHERE  #getstudentmarks.division_id = tbldivision.division_id

      UPDATE #getstudentmarks
      SET    #getstudentmarks.attended = #getstudent_attended.attended
      FROM   #getstudentmarks,
             #getstudent_attended
      WHERE  #getstudentmarks.student_id = #getstudent_attended.student_id

      UPDATE #getstudentmarks
      SET    #getstudentmarks.exempted = #getstudent_attended.exempted
      FROM   #getstudentmarks,
             #getstudent_attended
      WHERE  #getstudentmarks.student_id = #getstudent_attended.student_id

      UPDATE #getstudentmarks
      SET    attended = Isnull(attended, '0')

      UPDATE #getstudentmarks
      SET    exempted = Isnull(exempted, '0')

      UPDATE #getstudentmarks
      SET    total_attendance = Isnull(total_attendance, '0')

      --UPDATE #GetStudentMarks SET  #GetStudentMarks.AttendancePercentage=CAST(CAST((CAST(#GetStudentMarks.Attended AS NUMERIC(32,2)) * 100)/CAST(#GetStudentMarks.Total_Attendance AS NUMERIC(32,2)) AS NUMERIC(32,2)) AS VARCHAR(30))         
      --WHERE #GetStudentMarks.Total_Attendance <> '0'                                        
      UPDATE #getstudentmarks
      SET
      #getstudentmarks.attendancepercentage = Cast(
                                              Cast(
      Cast(( Cast(#getstudentmarks.attended AS NUMERIC(32, 2)) * 100 ) +
                          (
           Cast(
                                                 #getstudentmarks.exempted AS
                                                 NUMERIC(32, 2)) *
                                                   100 ) AS NUMERIC(32, 2)) /
      Cast
      (
      #getstudentmarks.total_attendance AS
      NUMERIC(
      32, 2)) AS NUMERIC(32, 2)) AS
                                              VARCHAR
                                              (30))
      WHERE  #getstudentmarks.total_attendance <> '0'

      --+ '' + '%'                      
      UPDATE #getstudentmarks
      SET    attendancepercentage = Isnull(attendancepercentage, '0.00')

      --UPDATE #GetStudentMarks SET  #GetStudentMarks.AttendancePercentage = '0 %' WHERE #GetStudentMarks.AttendancePercentage IS NULL             
      -------------end calculation---------------------        
      DECLARE @Roll_No              VARCHAR(20),
              @Stud_Id              VARCHAR(20),
              @Stud_Name            VARCHAR(200),
              @Subject_Name         VARCHAR(200),
              @Stud_Last_Name       VARCHAR(200),
              @AttendancePercentage VARCHAR(200)
      --  select * from #GetStudentMarks                 
      DECLARE @cntColm INT

      SELECT @cntColm = Count(roll_no)
      FROM   #getstudentmarks
      GROUP  BY roll_no

      CREATE TABLE #subject
        (
           sub_name VARCHAR(200)
        )

      INSERT INTO #subject
                  (sub_name)
      SELECT DISTINCT( subject_name )
      FROM   #getstudentmarks

      --print @cntColm              
      CREATE TABLE #getmarkssheet
        (
           student_id   VARCHAR(100),
           roll_no      VARCHAR(100),
           student_name VARCHAR(200)
        )

      --select * from #Subject             
      --------------- Cursor To add Columns As a Subject  Name-------------------    
      -- print'text'          
      DECLARE @Stubject VARCHAR(max)
      DECLARE curaddcol CURSOR FOR
        SELECT sub_name
        FROM   #subject

      OPEN curaddcol

      FETCH next FROM curaddcol INTO @Stubject

      WHILE @@FETCH_STATUS = 0
        BEGIN
            --print @Stubject             
            DECLARE @column VARCHAR(max)

            SELECT @column = Replace(@Stubject, '&', '')

            SELECT @column = Replace(@column, 'and', '')

            SELECT @column = Replace(@column, '.', '')

            SELECT @column = Replace(@column, ',', '')

            SELECT @column = Replace(@column, ' ', '')

            SELECT @column = Replace(@column, '-', '')

            SELECT @column = Replace(@column, '(', '')

            SELECT @column = Replace(@column, ')', '')

            SELECT @column = Replace(@column, '/', '')

            SELECT @column = Replace(@column, '//', '')

            SELECT @column = Replace(@column, '\', '')

            SELECT @column = Replace(@column, ':', '')

            --print 'columnname' + @column     
            IF( @column <> '' )
              BEGIN
                  EXEC('ALTER TABLE #GetMarksSheet ADD ' + @column +
                  ' VARCHAR(max)')
              --print @column  
              END

            SET @cntColm=@cntColm - 1

            FETCH next FROM curaddcol INTO @Stubject
        END

      ---------------------------- Cursor  Ends------------------------------------------            
      DECLARE cursubject CURSOR FOR
        SELECT roll_no,
               student_id,
               stud_name,
               stud_last_name,
               subject_name,
               attendancepercentage
        FROM   #getstudentmarks

      OPEN cursubject

      FETCH next FROM cursubject INTO @Roll_No, @Stud_Id, @Stud_Name,
      @Stud_Last_Name, @Subject_Name, @AttendancePercentage

      -- while  @cntColm >0              
      WHILE @@FETCH_STATUS = 0
        BEGIN
            DECLARE @ColName VARCHAR(max)

            SELECT @ColName = Replace(@Subject_Name, '&', '')

            SELECT @ColName = Replace(@ColName, 'and', '')

            SELECT @ColName = Replace(@ColName, ',', '')

            SELECT @ColName = Replace(@ColName, '.', '')

            SELECT @ColName = Replace(@ColName, ' ', '')

            SELECT @ColName = Replace(@ColName, '-', '')

            SELECT @ColName = Replace(@ColName, '(', '')

            SELECT @ColName = Replace(@ColName, ')', '')

            SELECT @ColName = Replace(@ColName, '/', '')

            SELECT @ColName = Replace(@ColName, '//', '')

            SELECT @ColName = Replace(@ColName, '\', '')

            SELECT @ColName = Replace(@ColName, ':', '')

            DECLARE @MarkInPer VARCHAR(max)

            SET @MarkInPer=Cast(@AttendancePercentage AS VARCHAR(max))

            IF NOT EXISTS (SELECT student_id
                           FROM   #getmarkssheet
                           WHERE  student_id = @Stud_Id)
              BEGIN
                  DECLARE @FullName VARCHAR(400)

                  --print @AttendancePercentage          
                  --print @ColName+'----'   +Cast(@MarkInPer as varchar(max))  +'----'    
                  -- select @MarkInPer=COALESCE(@MarkInPer,0)   
                  -- print @Roll_No + 'roll num'  
                  EXEC('insert into #GetMarksSheet(Student_Id,'+ @ColName +
                  ') values ('+
                  @Stud_Id +','+@MarkInPer + ')')

                  -- print @Stud_Name              
                  UPDATE #getmarkssheet
                  SET    student_name = @Stud_Name
                  WHERE  student_id = @Stud_Id
              --exec('UPDATE #GetMarksSheet SET  Student_Name='+@Stud_Name  +' where Roll_No='+@Roll_No)              
              END
            ELSE
              EXEC('UPDATE #GetMarksSheet SET '+ @ColName +' = '+@MarkInPer +
              ' where Student_Id='+@Stud_Id)

            SET @cntColm=@cntColm - 1

            FETCH next FROM cursubject INTO @Roll_No, @Stud_Id, @Stud_Name,
            @Stud_Last_Name, @Subject_Name, @AttendancePercentage
        END

      SELECT *
      FROM   #getmarkssheet
END 

Ouch. 哎哟。 Do it without temp tables and try it in one statement. 在没有临时表的情况下执行此操作,然后在一条语句中进行尝试。 It looks doable. 看起来可行。

Your approach kills the query optimizer's ability to optimize because you give it detailed steps including a (OUCH) cursoer which means single processor loop behavior as you DEMAND it. 您的方法破坏了查询优化器的优化能力,因为您给了它详细的步骤,包括(OUCH)光标,这意味着在您要求时单处理器循环行为。

This is NOT sql, this is a perversion - sql deals with sets. 这不是sql,这是一个变态-sql处理集合。

I am sure you CAN describ the result in one statement, without the use of temporary tables, and the result may surprise you performance wise ;) 我确信您可以在不使用临时表的情况下用一个语句描述结果,并且结果可能会使您对性能感到惊讶;)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM