UNION된 쿼리를 인서트시 실행계획이 바뀌어 다른값이 들어갑니다. 0 5 789

by matrixkdg [SQL Query] [2018.02.21 13:58:47]


안녕하세요.

이와같은 쿼리를 2개정도 더 만들어서 ( 상위 몇개 ) 유니온으로 잡은 뒤 셀렉트 날린결과와 인서트를 날린결과가 다르게 들어갑니다.

/*+ RULE */ 이라는 힌트를 사용해서 셀렉트 해보니 인서트시 잘못들어간 데이터가 나오더군요 인서트할경우 저 힌트가 들어간 실행계획을 타는것 같습니다.

각각 정렬을하고 유니온으로 잡는것때문에 문제가 되고있는거같습니다 각각 정렬을 해서 한데모아 집계를 해야해서 각각 정렬은 불가피한것같은데

실행계획이 변경되지 않게 인서트하도록 사용하는 힌트라던가 혹은 다른방법이 있는지 조언좀부탁드리겠습니다...

SELECT  *
                                                FROM (
                                                        SELECT   TELECOM_CD
                                                                        ,CERT_NUM                            
                                                                       ,SUM( IS_TOT_CNT ) IS_TOT_CNT
                                                                       ,SUM( NS_TOT_CNT ) NS_TOT_CNT                                
                                                                       ,SUM(TRUVIR_00) TRUVIR_00
                                                                       ,SUM( IS_TOT_CNT + NS_TOT_CNT ) IS_NS_CNT
                                                                       ,SUM( IS_TOT_CNT - TRUVIR_00 ) UVIR_ERR
                                                                       ,SUM( OCR_CHG_00) OCR_CHG_00
                                                                       ,SUM( OCR_CHG_01) OCR_CHG_01
                                                                       ,SUM( OCR_CHG_02) OCR_CHG_02
                                                        FROM    ICSM_SCANNER_OPEN_STAT_TB                                    
                                                        WHERE  OPEN_DT >= 20170101
                                                        AND    OPEN_DT <= 20170108    
                                                        AND     TELECOM_CD = 'F3001'
                                                        GROUP BY CERT_NUM                                    
                                                            ORDER BY IS_NS_CNT DESC,  UVIR_ERR DESC  , NS_TOT_CNT DESC                                    
                                                      ) 
                                                WHERE 1=1                            
                                                      AND    ROWNUM <= 200       

by 마농 [2018.02.21 14:09:45]

정렬 후 200 건을 걸러내는데 정렬 조건이 유니크하지 않네요?
200 등 언저리에 있는 정렬기준 값들이 동일한 경우 어떤 행이 선택될지 미지수네요.
유니크한 정렬조건을 추가하세요. (예: PK, ROWID 등)
추가로.
각각 유니온 하는 쿼리 볼 수 있을까요?
하나로 합치는게 가능하리라 생각됩니다.


by matrixkdg [2018.02.21 14:27:16]

답변감사합니다.

이런식으로 묶어서  하나로 만들어 TELECOM_CD 기준으로 그룹하여 집계를 합니다      

                                 SELECT  *
                                                FROM (
                                                        SELECT   TELECOM_CD
                                                                        ,CERT_NUM                            
                                                                       ,SUM( IS_TOT_CNT ) IS_TOT_CNT
                                                                       ,SUM( NS_TOT_CNT ) NS_TOT_CNT                                
                                                                       ,SUM(TRUVIR_00) TRUVIR_00
                                                                       ,SUM( IS_TOT_CNT + NS_TOT_CNT ) IS_NS_CNT
                                                                       ,SUM( IS_TOT_CNT - TRUVIR_00 ) UVIR_ERR
                                                                       ,SUM( OCR_CHG_00) OCR_CHG_00
                                                                       ,SUM( OCR_CHG_01) OCR_CHG_01
                                                                       ,SUM( OCR_CHG_02) OCR_CHG_02
                                                        FROM    ICSM_SCANNER_OPEN_STAT_TB                                    
                                                        WHERE  OPEN_DT >= 20170101
                                                        AND    OPEN_DT <= 20170108    
                                                        AND     TELECOM_CD = 'F3001'
                                                        GROUP BY TELECOM_CD,CERT_NUM                                    
                                                            ORDER BY IS_NS_CNT DESC,  UVIR_ERR DESC  , NS_TOT_CNT DESC                                    
                                                      ) 
                                                WHERE 1=1                            
                                                      AND    ROWNUM <= 200                                      
                                    UNION                          
                                             SELECT  *
                                            FROM (
                                                    SELECT   TELECOM_CD
                                                                    ,CERT_NUM                            
                                                                   ,SUM( IS_TOT_CNT ) IS_TOT_CNT
                                                                   ,SUM( NS_TOT_CNT ) NS_TOT_CNT                                
                                                                   ,SUM(TRUVIR_00) TRUVIR_00
                                                                   ,SUM( IS_TOT_CNT + NS_TOT_CNT ) IS_NS_CNT
                                                                   ,SUM( IS_TOT_CNT - TRUVIR_00 ) UVIR_ERR
                                                                   ,SUM( OCR_CHG_00) OCR_CHG_00
                                                                   ,SUM( OCR_CHG_01) OCR_CHG_01
                                                                   ,SUM( OCR_CHG_02) OCR_CHG_02
                                                    FROM    ICSM_SCANNER_OPEN_STAT_TB                                    
                                                    WHERE  OPEN_DT >= 20170101
                                                    AND    OPEN_DT <= 20170108    
                                                    AND     TELECOM_CD = 'F3002'
                                                    GROUP BY TELECOM_CD,CERT_NUM                                        
                                                        ORDER BY IS_NS_CNT DESC,  UVIR_ERR DESC  , NS_TOT_CNT DESC                                    
                                                  ) 
                                            WHERE 1=1                            
                                                  AND    ROWNUM <= 200                                     
                                    UNION 
                                              SELECT  *
                                            FROM (
                                                    SELECT   TELECOM_CD
                                                                    ,CERT_NUM                            
                                                                   ,SUM( IS_TOT_CNT ) IS_TOT_CNT
                                                                   ,SUM( NS_TOT_CNT ) NS_TOT_CNT                                
                                                                   ,SUM(TRUVIR_00) TRUVIR_00
                                                                   ,SUM( IS_TOT_CNT + NS_TOT_CNT ) IS_NS_CNT
                                                                   ,SUM( IS_TOT_CNT - TRUVIR_00 ) UVIR_ERR
                                                                   ,SUM( OCR_CHG_00) OCR_CHG_00
                                                                   ,SUM( OCR_CHG_01) OCR_CHG_01
                                                                   ,SUM( OCR_CHG_02) OCR_CHG_02
                                                    FROM    ICSM_SCANNER_OPEN_STAT_TB                                    
                                                    WHERE  OPEN_DT >= 20170101
                                                    AND    OPEN_DT <= 20170108    
                                                    AND     TELECOM_CD = 'F3003'
                                                    GROUP BY TELECOM_CD,CERT_NUM                                        
                                                        ORDER BY IS_NS_CNT DESC,  UVIR_ERR DESC  , NS_TOT_CNT DESC                                    
                                                  ) 
                                            WHERE 1=1                            
                                                  AND    ROWNUM <= 200   


by 마농 [2018.02.21 14:38:42]

open_dt 의 자료형이 숫자형 인가요?
숫자가 아닌데 숫자 조건 준다면 성능에 문제가 생길 수 있습니다.


by 마농 [2018.02.21 14:37:11]
SELECT *
  FROM (SELECT telecom_cd
             , cert_num
             , SUM(is_tot_cnt) is_tot_cnt
             , SUM(ns_tot_cnt) ns_tot_cnt
             , SUM(truvir_00 ) truvir_00
             , SUM(is_tot_cnt + ns_tot_cnt) is_ns_cnt
             , SUM(is_tot_cnt - truvir_00 ) uvir_err
             , SUM(ocr_chg_00) ocr_chg_00
             , SUM(ocr_chg_01) ocr_chg_01
             , SUM(ocr_chg_02) ocr_chg_02
             , ROW_NUMBER() OVER(
               PARTITION BY telecom_cd
               ORDER BY SUM(is_tot_cnt + ns_tot_cnt) DESC
                      , SUM(is_tot_cnt - truvir_00 ) DESC
                      , SUM(ns_tot_cnt) DESC
                      , cert_num    -- Unique 항목 추가
               ) rn
          FROM icsm_scanner_open_stat_tb
         WHERE open_dt >= '20170101'
           AND open_dt <= '20170108'
           AND telecom_cd IN ('F3001', 'F3002', 'F3003')
         GROUP BY telecom_cd, cert_num
        )
 WHERE 1=1
   AND rn <= 200
;

 


by matrixkdg [2018.02.21 14:51:38]

와 첫댓글 주신부분 참고하여 쿼리를 수정하여 정상적인 결과를 얻었는데

이렇게 하니까 정말 간단하게나오네요;; 

이렇게 또 하나 배워가네요 정말 감사드립니다.

댓글등록
SQL문을 포맷에 맞게(깔끔하게) 등록하려면 code() 버튼을 클릭하여 작성 하시면 됩니다.
로그인 사용자만 댓글을 작성 할 수 있습니다. 로그인, 회원가입