使用内部联接更新查询的速度很慢

时间:2015-07-06 11:10:18

标签: sql sql-server

我使用以下查询根据指定的条件更新一列。我正在使用“内部联接”,但即使它不必更新任何记录(0条记录),运行查询也需要15秒以上。

UPDATE CONFIGURATION_LIST
SET DUPLICATE_SERIAL_NUM = 0
FROM CONFIGURATION_LIST
INNER JOIN (SELECT DISTINCT APPLIED_MAT_CODE, APPLIED_SERIAL_NUMBER, COUNT(*) AS NB
            FROM CONFIGURATION_LIST
            WHERE
                PLANT = '0067'
                AND APPLIED_SERIAL_NUMBER IS NOT NULL 
                AND APPLIED_SERIAL_NUMBER !=''
                AND DUPLICATE_SERIAL_NUM = 1
            GROUP BY 
                APPLIED_MAT_CODE, APPLIED_SERIAL_NUMBER
            HAVING
                COUNT(*) = 1) T2 ON T2.APPLIED_SERIAL_NUMBER = CONFIGURATION_LIST.APPLIED_SERIAL_NUMBER
                                 AND T2.APPLIED_MAT_CODE = CONFIGURATION_LIST.APPLIED_MAT_CODE
WHERE 
    CONFIGURATION_LIST.PLANT = '0067'
    AND DUPLICATE_SERIAL_NUM = 1

索引与APPLIED_SERIAL_NUMBERAPPLIED_MAT_CODE一致,碎片也很好。

请您帮我解决上述查询效果。

3 个答案:

答案 0 :(得分:1)

首先,在使用DISTINCT时,您不需要GROUP BY。 SQL Server可能会忽略它,但无论如何这都是一个坏主意:

UPDATE CONFIGURATION_LIST
SET DUPLICATE_SERIAL_NUM = 0
    FROM CONFIGURATION_LIST INNER JOIN
         (SELECT APPLIED_MAT_CODE, APPLIED_SERIAL_NUMBER, COUNT(*) AS NB
          FROM CONFIGURATION_LIST cl
          WHERE cl.PLANT = '0067' AND
                cl.APPLIED_SERIAL_NUMBER IS NOT NULL AND
                cl.APPLIED_SERIAL_NUMBER <> ''
                cl.DUPLICATE_SERIAL_NUM = 1
          GROUP BY cl.APPLIED_MAT_CODE, cl.APPLIED_SERIAL_NUMBER
          HAVING COUNT(*) = 1
         ) T2
         ON T2.APPLIED_SERIAL_NUMBER = CONFIGURATION_LIST.APPLIED_SERIAL_NUMBER AND
            T2.APPLIED_MAT_CODE = CONFIGURATION_LIST.APPLIED_MAT_CODE
WHERE CONFIGURATION_LIST.PLANT = '0067' AND
      DUPLICATE_SERIAL_NUM = 1;

对于此查询,您需要以下索引:CONFIGURATION_LIST(PLANT, DUPLICATE_SERIAL_NUM, APPLIED_SERIAL_NUMBER, APPLIED_MAT_CODE, APPLIED_SERIAL_NUMBER)

HAVING COUNT(*) = 1表示您可能真的想要NOT EXISTS(通常会更快)。但是你没有真正解释查询应该做什么,你只是说这段代码很慢。

答案 1 :(得分:1)

看起来您正在检查表中存在于同一个表中的具有相同值的行,如果没有,则将重复列更新为零。如果您的表具有唯一键(标识字段或复合键),您可以执行以下操作:

UPDATE C
SET C.DUPLICATE_SERIAL_NUM = 0
FROM 
  CONFIGURATION_LIST C
where 
  not exists (
    select
      1 
    FROM
      CONFIGURATION_LIST C2
    where
      C2.APPLIED_SERIAL_NUMBER = C.APPLIED_SERIAL_NUMBER and
      C2.APPLIED_MAT_CODE = C.APPLIED_MAT_CODE and
      C2.UNIQUE_KEY_HERE != C.UNIQUE_KEY_HERE
  ) and 
  C.PLANT = '0067' and
  C.DUPLICATE_SERIAL_NUM = 1

答案 2 :(得分:0)

我会首先尝试选择:

select APPLIED_MAT_CODE, APPLIED_SERIAL_NUMBER, count(*) as n
from CONFIGURATION_LIST cl
where
    cl.PLANT='0067' and
    cl.APPLIED_SERIAL_NUMBER IS NOT NULL and
    cl.APPLIED_SERIAL_NUMBER <> ''
group by APPLIED_MAT_CODE, APPLIED_SERIAL_NUMBER;

您获得了多少行以及需要多长时间?

如果从表中删除DUPLICATE_SERIAL_NUM列,则可能非常简单。 DUPLICATE_SERIAL_NUM表示您正在搜索重复项。在计算行数时,可以引入一个包含计数的简单表:

create table CLCOUNT ( N int unsigned, C int /* or what APPLIED_MAT_CODE is */, S int /* or what APPLIED_SERIAL_NUMBER is */, PLANT char(20) /* or what PLANT is */, index unique (C,S,PLANT), index(PLANT,N));
insert into CLCOUNT select count(*), cl.APPLIED_MAT_CODE, cl.APPLIED_SERIAL_NUMBER, cl.PLANT
from CONFIGURATION_LIST cl
where
    cl.PLANT='0067' and
    cl.APPLIED_SERIAL_NUMBER IS NOT NULL and
    cl.APPLIED_SERIAL_NUMBER <> ''
group by APPLIED_MAT_CODE, APPLIED_SERIAL_NUMBER;

这需要多长时间?

现在您可以简单地select * from CLCOUNT where PLANT='0067' and N=1;

这远非完美。但是你应该能够分析(EXPLAIN SELECT ...)你的查询并找出它需要这么长时间的原因。