SQL(NOT IN)查询需要永远执行

时间:2013-11-08 12:47:48

标签: sql sql-server query-optimization

我有一个查询,需要超过2小时来执行百万条记录,我不知道如何优化它以使其运行速度更快。 Here是表和查询的sql小提琴。

WITH frm 
     AS (SELECT product_id                               AS PId, 
                Min(Cast(product_startdate AS DATETIME)) AS PStartDate 
         FROM   products 
         WHERE  product_status IN ( 'F', 'R', 'M' ) 
         GROUP  BY product_id), 
     firstcount 
     AS (SELECT pid, 
                pstartdate, 
                (SELECT Count(*) 
                 FROM   products 
                 WHERE  product_id IN ((SELECT product_id 
                                        FROM   products 
                                        WHERE  product_status IN ( 'OR', 'OP' ) 
                                               AND product_comments LIKE 
                                                   '%CANCELLED%' 
                                        EXCEPT 
                                        (SELECT product_id 
                                         FROM   products 
                                         WHERE  product_status = 'DE' 
                                         UNION 
                                         SELECT product_id 
                                         FROM   products 
                                         WHERE  product_status = 'OR' 
                                                AND product_comments NOT LIKE 
                                                    '%CANCELLED%')) 
                                       EXCEPT 
                                       (SELECT product_id 
                                        FROM   products 
                                        WHERE  product_status IN ( 
                                               'RE', 'C', 'S', 'D' ) 
                                       )) 
                        AND product_id = pid) AS v_count 
         FROM   frm), 
     secondcount 
     AS (SELECT pid, 
                pstartdate, 
                CASE 
                  WHEN v_count = 0 THEN (SELECT Count(*) 
                                         FROM   products 
                                         WHERE  product_id IN 
                  ( 
                  SELECT product_id 
                  FROM   [dbo].products 
                  WHERE 
                                                product_status IN ( 'F', 
                                                'R', 'M' ) 
                                                AND product_startdate != 
                                                    '.' 
                                                               EXCEPT 
                                                               (SELECT 
                  product_id 
                                                                FROM   products 
                                                                WHERE 
                                                product_status = 'DE' 
                                                                UNION 
                                                                SELECT 
                  product_id 
                                                                FROM   products 
                                                                WHERE 
                                                product_status = 'OR' 
                                                AND product_comments NOT 
                                                    LIKE '%CANCELLED%') 
                                                               EXCEPT 
                                                               (SELECT 
                  product_id 
                                                                FROM   products 
                                                                WHERE 
                                                product_status IN ( 'OR', 
                                                'OP' ) 
                                                AND product_comments LIKE 
                                                    '%CANCELLED%' 
                                                                EXCEPT 
                                                                (SELECT 
                  product_id 
                                                                 FROM   products 
                                                                 WHERE 
                                                 product_status = 
                                                 'DE' 
                                                                 UNION 
                                                SELECT product_id 
                                                FROM   products 
                                                WHERE  product_status = 
                                                       'OR' 
                                                       AND product_comments NOT 
                                                           LIKE '%CANCELLED%')) 
                                                               EXCEPT 
                                                               (SELECT 
                  product_id 
                                                                FROM   products 
                                                                WHERE 
                                                product_status IN ( 'RE', 
                                                'C', 'S', 'D' ))) 
                                                AND product_id = pid) 
                  ELSE v_count 
                END AS v_count 
         FROM   firstcount) 
INSERT INTO products_del 
            (product_id, 
             product_startdate, 
             productdel_status) 
SELECT pid, 
       pstartdate, 
       CASE 
         WHEN v_count != 0 THEN 'UNKNOWN' 
         ELSE NULL 
       END 
FROM   secondcount 

SELECT * 
FROM   products_del 

1 个答案:

答案 0 :(得分:1)

请尝试以下方法。我通过删除不必要的INUNIONEXCEPT子句来简化内部查询。

WITH frm 
     AS (SELECT product_id                               AS PId, 
                Min(Cast(product_startdate AS DATETIME)) AS PStartDate 
         FROM   products 
         WHERE  product_status IN ( 'F', 'R', 'M' ) 
         GROUP  BY product_id), 
     firstcount 
     AS (SELECT pid, 
                pstartdate, 
                (SELECT Count(*) 
                 FROM   products 
                 WHERE  product_status IN ( 'OR', 'OP' ) 
                   AND product_comments LIKE '%CANCELLED%' 
                   AND product_id = pid) AS v_count 
         FROM   frm), 
     secondcount 
     AS (SELECT pid, 
                pstartdate, 
                CASE 
                  WHEN v_count = 0 THEN (SELECT Count(*) 
                                         FROM   products 
                                         WHERE  product_status IN ( 'F', 'R', 'M' ) 
                                                AND product_startdate != '.' 
                                                AND product_id = pid) 
                  ELSE v_count 
                END AS v_count 
         FROM   firstcount) 
INSERT INTO products_del 
            (product_id, 
             product_startdate, 
             productdel_status) 
SELECT pid, 
       pstartdate, 
       CASE 
         WHEN v_count != 0 THEN 'UNKNOWN' 
         ELSE NULL 
       END 
FROM   secondcount 

SELECT * 
FROM   products_del