開發過程中遇到的SQL優化

  1. 需求描述
    對一些業務數據以報表的形式進行展示,在項目上線前統計數據不準確(忽略了節假日的統計)和查詢速度慢。統計的是職員處理業務的執行率(默認發公告給你,你在正常工作日的一天之內處理就是及時處理)。
  2. 原始版本
    日期格式的操作用的是to_char,導致索引沒有命中,查詢較慢。報表的頁面引入多餘的js,使得後臺數據返回前臺,前臺加載數據的時候還要幾秒。
  3. 優化後的版本
    涉及到的日期格式用to_date,處理及時不及時考慮到節假日。
SELECT DECODE(TT.TASK_NUM_TOTAL, NULL, 0, TT.TASK_NUM_TOTAL) TASK_NUM_TOTAL,
       DECODE(TT.TASK_NUM_COMP, NULL, 0, TT.TASK_NUM_COMP) TASK_NUM_COMP,
       DECODE(TT.TASK_NUM_TIME, NULL, 0, TT.TASK_NUM_TIME) TASK_NUM_TIME,
       DECODE(TT.TASK_NUM_TOTAL,
              0,
              0,
              round((TT.TASK_NUM_TIME * 100) / TT.TASK_NUM_TOTAL, 2)) || '%' TASK_NUMBER_TIME_PERCENT,
       DECODE(TT.TASK_NUM_TOTAL,
              0,
              0,
              round((TT.TASK_NUM_TIME * 100) / TT.TASK_NUM_TOTAL, 2)) TASK_NUMBER_TIME_SCALE,
       TT.FULLNAME,
       TT.USERID
  FROM (SELECT DECODE(T.TASK_NUM_TOTAL, NULL, 0, T.TASK_NUM_TOTAL) TASK_NUM_TOTAL,
               DECODE(T.TASK_NUM_COMP, NULL, 0, T.TASK_NUM_COMP) TASK_NUM_COMP,
               DECODE(T.TASK_NUM_TIME, NULL, 0, T.TASK_NUM_TIME) TASK_NUM_TIME,
               V.FULLNAME,
               V.USERID
          FROM (SELECT A.TASK_NUM_TOTAL,
                       B.TASK_NUM_COMP,
                       C.TASK_NUM_TIME,
                       A.USERID
                  FROM (SELECT COUNT(O.TC_TASK_CONTENT_ID) TASK_NUM_TOTAL, O.TASK_HANDLE_PERSON USERID
                          FROM TC_TASK_CONTENT O
                          WHERE 1 = 1
                          AND O.TASK_CREATE_DATE >= TO_DATE(?, 'YYYY-MM-DD')
                          AND O.TASK_CREATE_DATE < TO_DATE(?, 'YYYY-MM-DD')+1 

                         GROUP BY O.TASK_HANDLE_PERSON) A,
                       (SELECT COUNT(O.TC_TASK_CONTENT_ID) TASK_NUM_COMP, O.TASK_HANDLE_PERSON USERID
                          FROM TC_TASK_CONTENT O
                         WHERE O.TASK_STATE = '2'
                          AND O.TASK_CREATE_DATE >= TO_DATE(?, 'YYYY-MM-DD')
                          AND O.TASK_CREATE_DATE < TO_DATE(?, 'YYYY-MM-DD')+1 

                         GROUP BY O.TASK_HANDLE_PERSON) B,
                       (SELECT COUNT(O.TC_TASK_CONTENT_ID) TASK_NUM_TIME, O.TASK_HANDLE_PERSON USERID
                          FROM TC_TASK_CONTENT O
                         WHERE O.TASK_STATE = '2'
                          AND O.TASK_CREATE_DATE >= TO_DATE(?, 'YYYY-MM-DD')
                          AND O.TASK_CREATE_DATE < TO_DATE(?, 'YYYY-MM-DD')+1 

                           AND TRUNC(O.ACTUAL_FINISH_DATE-O.TASK_CREATE_DATE)<=1
                         GROUP BY O.TASK_HANDLE_PERSON) C
                 WHERE A.USERID = B.USERID(+)
                   AND B.USERID = C.USERID(+)) T,
               USERS_ORGS UO,
               USER_ U,
               (SELECT ORGANIZATIONID
                  FROM ORGANIZATION_ T
                CONNECT BY PRIOR T.ORGANIZATIONID = T.PARENTORGANIZATIONID
                  START WITH ORGANIZATIONID = '"+MapUtil.getString(inputData, "ORGANIZATIONID")+"') ORG,
               V_USER_ORG V
         WHERE UO.ORGANIZATIONID = ORG.ORGANIZATIONID
           AND T.USERID(+) = U.USERID
           AND U.USERID = UO.USERID
           AND V.USERID = U.USERID
        UNION ALL
        SELECT SUM(DECODE(T.TASK_NUM_TOTAL, NULL, 0, T.TASK_NUM_TOTAL)) TASK_NUM_TOTAL,
               SUM(DECODE(T.TASK_NUM_COMP, NULL, 0, T.TASK_NUM_COMP)) TASK_NUM_COMP,
               SUM(DECODE(T.TASK_NUM_TIME, NULL, 0, T.TASK_NUM_TIME)) TASK_NUM_TIME,
               '合計' FULLNAME,
               111111 USERID
          FROM (SELECT A.TASK_NUM_TOTAL,
                       B.TASK_NUM_COMP,
                       C.TASK_NUM_TIME,
                       A.USERID
                  FROM (SELECT COUNT(O.TC_TASK_CONTENT_ID) TASK_NUM_TOTAL, O.TASK_HANDLE_PERSON USERID
                          FROM TC_TASK_CONTENT O
                          WHERE 1 = 1
                          AND O.TASK_CREATE_DATE >= TO_DATE(?, 'YYYY-MM-DD')
                          AND O.TASK_CREATE_DATE < TO_DATE(?, 'YYYY-MM-DD')+1 

                         GROUP BY O.TASK_HANDLE_PERSON) A,
                       (SELECT COUNT(O.TC_TASK_CONTENT_ID) TASK_NUM_COMP, O.TASK_HANDLE_PERSON USERID
                          FROM TC_TASK_CONTENT O
                         WHERE O.TASK_STATE = '2'
                          AND O.TASK_CREATE_DATE >= TO_DATE(?, 'YYYY-MM-DD')
                          AND O.TASK_CREATE_DATE < TO_DATE(?, 'YYYY-MM-DD')+1 

                         GROUP BY O.TASK_HANDLE_PERSON) B,
                       (SELECT COUNT(O.TC_TASK_CONTENT_ID) TASK_NUM_TIME, O.TASK_HANDLE_PERSON USERID
                          FROM TC_TASK_CONTENT O
                         WHERE O.TASK_STATE = '2'

                          AND O.TASK_CREATE_DATE >= TO_DATE(?, 'YYYY-MM-DD')
                          AND O.TASK_CREATE_DATE < TO_DATE(?, 'YYYY-MM-DD')+1 
                           AND TRUNC(O.ACTUAL_FINISH_DATE-O.TASK_CREATE_DATE)<=1
                         GROUP BY O.TASK_HANDLE_PERSON) C
                 WHERE A.USERID = B.USERID(+)
                   AND B.USERID = C.USERID(+)) T,
               USERS_ORGS UO,
               USER_ U,
               (SELECT ORGANIZATIONID
                  FROM ORGANIZATION_ T
                CONNECT BY PRIOR T.ORGANIZATIONID = T.PARENTORGANIZATIONID
                  START WITH ORGANIZATIONID = '"+MapUtil.getString(inputData, "ORGANIZATIONID")+"') ORG,
               V_USER_ORG V
         WHERE T.USERID(+) = U.USERID
           AND U.USERID = UO.USERID
           AND UO.ORGANIZATIONID = ORG.ORGANIZATIONID
           AND V.USERID = U.USERID) TT
  1. 最終版本
WITH ALL_ORG AS
 (SELECT ORGANIZATIONID,
         DECODE(LEVEL, 2, ORGANIZATIONID, 3, T.PARENTORGANIZATIONID) THIRDID
    FROM ORGANIZATION_ T
  CONNECT BY PRIOR T.ORGANIZATIONID = T.PARENTORGANIZATIONID
   START WITH ORGANIZATIONID = '5272'),
ORG_SUM AS
 (SELECT DECODE(T.TASK_NUM_TOTAL, NULL, 0, T.TASK_NUM_TOTAL) TASK_NUM_TOTAL,
         DECODE(T.TASK_NUM_COMP, NULL, 0, T.TASK_NUM_COMP) TASK_NUM_COMP,
         DECODE(T.TASK_NUM_TIME, NULL, 0, T.TASK_NUM_TIME) TASK_NUM_TIME,
         (SELECT OZ.NAME
            FROM ORGANIZATION_ OZ
           WHERE OZ.ORGANIZATIONID = T.THIRDID) FULLNAME,
         T.THIRDID
    FROM (SELECT A.TASK_NUM_TOTAL,
                A.TASK_NUM_COMP,
                 A.TASK_NUM_TIME,
                 A.THIRDID
            FROM (SELECT SUM(1) TASK_NUM_TOTAL,
                               SUM(CASE
                                     WHEN TRUNC(O.ACTUAL_FINISH_DATE -
                                                O.TASK_CREATE_DATE) <= 1 THEN
                                      1
                                     ELSE
                                      0
                                   END) TASK_NUM_TIME,
                               SUM(DECODE(TASK_STATE, '2', 1, 0)) TASK_NUM_COMP,
                               O.TASK_HANDLE_PERSON USERID, TT.THIRDID
                          FROM TC_TASK_CONTENT O,USERS_ORGS UO,ALL_ORG TT
                         WHERE O.TASK_HANDLE_PERSON = UO.USERID
                     AND UO.ORGANIZATIONID = TT.ORGANIZATIONID
                     AND TT.THIRDID IS NOT NULL
                           AND O.TASK_CREATE_DATE >= TO_DATE('2017-01-01', 'YYYY-MM-DD')
                           AND O.TASK_CREATE_DATE <
                               TO_DATE('2017-12-31', 'YYYY-MM-DD') + 1
                         GROUP BY TT.THIRDID) A) T),
OGR_ALL AS
 (SELECT S.*
    FROM ORG_SUM S)
SELECT DECODE(TT.TASK_NUM_TOTAL, NULL, 0, TT.TASK_NUM_TOTAL) TASK_NUM_TOTAL,
       DECODE(TT.TASK_NUM_COMP, NULL, 0, TT.TASK_NUM_COMP) TASK_NUM_COMP,
       DECODE(TT.TASK_NUM_TIME, NULL, 0, TT.TASK_NUM_TIME) TASK_NUM_TIME,
       DECODE(TT.TASK_NUM_TOTAL,
              0,
              0,
              ROUND((TT.TASK_NUM_TIME * 100) / TT.TASK_NUM_TOTAL, 2)) || '%' TASK_NUMBER_TIME_PERCENT,
       DECODE(TT.TASK_NUM_TOTAL,
              0,
              0,
              ROUND((TT.TASK_NUM_TIME * 100) / TT.TASK_NUM_TOTAL, 2)) TASK_NUMBER_TIME_SCALE,
       TT.FULLNAME,
       TT.THIRDID
  FROM OGR_ALL TT

附帶查詢的結果圖:
這裏寫圖片描述
5. 討論
判斷某一天是否屬於上班時間?知道某一天,這一天的5個工作日是幾月幾號?現在對於工作日的判斷是將一年的日期放進表裏面維護,判斷5個工作後是幾月幾號用的是遞歸。感覺這樣的做法很繁瑣而且效率很慢,但是沒有什麼其他的好辦法。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章