2011-05-02 8 views
8

오랜 시간이 걸리는 프로덕션의 쿼리를 최적화하려고합니다. 목표는 일치하는 필드 값 기준에 따라 중복 레코드를 찾은 다음 삭제하는 것입니다. 현재 쿼리는 t1.col1 = t2.col1의 내부 조인을 통한 자체 조인을 사용하고 값을 확인하기위한 where 절을 사용합니다.복제본을 검사 할 때 최상의자가 결합 기술

select * from table t1 
inner join table t2 on t1.col1 = t2.col1 
where t1.col2 = t2.col2 ... 

이 작업을 수행하는 더 좋은 방법은 무엇입니까? 또는 인덱스를 기반으로 모두 동일합니까? 어쩌면

select * from table t1, table t2 
where t1.col1 = t2.col1, t2.col2 = t2.col2 ... 

이 표에는 100m + 행이 있습니다.

MS SQL, SQL 서버 2008 엔터프라이즈

select distinct t2.id 
    from table1 t1 with (nolock) 
    inner join table1 t2 with (nolock) on t1.ckid=t2.ckid 
    left join table2 t3 on t1.cid = t3.cid and t1.typeid = t3.typeid 
    where 
    t2.id > @Max_id and 
    t2.timestamp > t1.timestamp and 
    t2.rid = 2 and 
    isnull(t1.col1,'') = isnull(t2.col1,'') and 
    isnull(t1.cid,-1) = isnull(t2.cid,-1) and 
    isnull(t1.rid,-1) = isnull(t2.rid,-1)and 
    isnull(t1.typeid,-1) = isnull(t2.typeid,-1) and 
    isnull(t1.cktypeid,-1) = isnull(t2.cktypeid,-1) and 
    isnull(t1.oid,'') = isnull(t2.oid,'') and 
    isnull(t1.stypeid,-1) = isnull(t2.stypeid,-1) 

    and (
      (
       t3.uniqueoid = 1 
      ) 
      or 
      (
       t3.uniqueoid is null and 
       isnull(t1.col1,'') = isnull(t2.col1,'') and 
       isnull(t1.col2,'') = isnull(t2.col2,'') and 
       isnull(t1.rdid,-1) = isnull(t2.rdid,-1) and 
       isnull(t1.stid,-1) = isnull(t2.stid,-1) and 
       isnull(t1.huaid,-1) = isnull(t2.huaid,-1) and 
       isnull(t1.lpid,-1) = isnull(t2.lpid,-1) and 
       isnull(t1.col3,-1) = isnull(t2.col3,-1) 
      ) 
    ) 
+0

MS SQL? 그렇다면 SQL Server의 버전은 무엇입니까? –

+0

@Bruno 죄송합니다. 질문과 태그를 업데이트했습니다. –

+0

@Mitch 아니오 동일한 테이블에 가입하는 하나의 테이블입니다. 자체 가입이 아닌 방법은 무엇입니까? –

답변

13

:이 집계 질문이다.

--DELETE table 
--WHERE KeyCol NOT IN (
select 
    MIN(KeyCol) AS RowToKeep, 
    col1, col2, 
from 
    table 
GROUP BY 
    col12, col2 
HAVING 
    COUNT(*) > 1 
--) 

그러나, 시간이 좀 걸릴 것입니다 ... 당신은 COL1, COL2에 인덱스를 바랍니다. 있음 look at bulk delete techniques

+0

+1 - 아마도 가장 빠른 실행 대답은 – JNK

+0

입니다. 질의 (열/테이블 이름이 변경됨)로 내 질문을 업데이트했습니다. 귀하의 제안은 여전히 ​​유효합니까? –

+0

@ Titan278 :해야합니다. ISNULL로 GROUP BY 할 필요가 없으며 table2/t3 확인을 위해 EXISTS를 사용해야합니다 (DISTINCT의 사용을 피하십시오) – gbn

1

당신은() 하나 개의 테이블에서 중복 행을 찾을 ROW_NUMBER를 사용할 수 있습니다.

당신은 here

+0

이 테이블 크기 이상으로 불쾌해질 것입니다. 집계를 사용합니다. – gbn

+0

네, 행이 완전히 같으면 적어도 간단하게 집계가 작동한다고 생각하지 않습니다. –

+0

당신은 PK가 없다고 가정합니다 : 당신은 PK 외부에서 복제본을 가질 수 있습니다. OP의 업데이트 된 쇼에는 PK가 있지만 여전히 중복됩니다. ROW_NUMBER가 개처럼 실행된다는 사실은 변경되지 않습니다. – gbn

0

중복을 감지하기 위해 확인하실 수 있습니다, 당신은 가입 할 필요가 없습니다 :

SELECT col1, col2 
FROM table 
GROUP BY col1, col2 
HAVING COUNT(*) > 1 

훨씬 더 빨리되어야한다.

+0

은 1 억 개의 행 테이블에 있습니까? 나는 그렇게 생각하지 않는다! –

+0

@Mitch Wheat : 모든 기술은 100m 이상의 행과 같이 실행됩니다. 특히 ROW_NUMBER 기반 기능 – gbn

+2

@Mitch : 실용적인 질문은 "x 초에 undex에서 실행될이 글을 쓰는 방법이 있습니까?" "원하는 결과를 얻을 수있는 가장 빠른 쿼리는 무엇입니까?" – Jay

1

두 가지 방법은 동등해야합니다. 나는 대부분의 SQL 엔진이 두 경우 모두 똑같은 일을한다고 생각한다.

그리고, 이것은 작동하지 않습니다. 당신은 적어도 하나의 필드가 다르거 나 모든 레코드가 일치해야합니다.

당신은 뭔가 더 같은 시도 할 수 있습니다 : 자기가 가입 왜

select col1, col2, col3 
from table 
group by col1, col2, col3 
having count(*)>1 
1

100m + 행이있는 테이블의 경우 GROUPBY 함수 사용 및 보관 테이블 사용이 최적화됩니다. 네 개의 쿼리로 변환하더라도.

1 단계 : 유지 키를 만듭니다

SELECT col1, col2, col3=count(*) 
INTO holdkey 
FROM t1 
GROUP BY col1, col2 
HAVING count(*) > 1 

2 단계 : holddups에 모든 중복 항목을 누르십시오. 이 작업은 4 단계

SELECT DISTINCT t1.* 
INTO holddups 
FROM t1, holdkey 
WHERE t1.col1 = holdkey.col1 
AND t1.col2 = holdkey.col2 

3 단계가 필요합니다 : 원본 테이블에서 중복 행을 삭제합니다.

DELETE t1 
FROM t1, holdkey 
WHERE t1.col1 = holdkey.col1 
AND t1.col2 = holdkey.col2 

4 단계 : 원래 테이블의 고유 행을 넣습니다.예를 들어 : 내 경험에

INSERT t1 SELECT * FROM holddups 
0

, SQL Server 성능은 OR 조건 정말 나쁜 것입니다. 아마도 자체 조인은 아니지만 나쁜 성능을 초래하는 table3과의 조화입니다. 그러나 그 계획을 보지 않으면 나는 확신하지 못할 것이다. 이 경우

,이 두 가지에 검색어를 분할하는 데 도움이 될 수 있습니다 다음 WHERE 표 3의 다른 conditons에 대한 조건과와 조건 t3.uniqueoid = 1과 하나가 다른 하나를 추가 할 UNION ALL를 사용 WHERE A를 하나.

관련 문제