2012-11-22 1 views
1

(PROPERTY_ID, GPSTIME, STATION_ID, PROPERTY_TYPE, VALUE)과 같은 열이있는 테이블이 있습니다. 여기서 PROPERTY_ID는 기본 키이고 STATION_ID는 외래 키입니다.MySQL에서 연속 된 중복 행을 제거하는 효율적인 방법

이 테이블은 상태 변경을 기록합니다. 각 행은 주어진 시간에 일부 스테이션의 속성 값을 나타냅니다. 그러나 각 속성이 열 (예 : (STATION_ID, GPSTIME, PROPERTY1, PROPERTY2, PROPERTY3, ...)) 인 이전 테이블에서 데이터가 변환되었습니다. 일반적으로 한 번에 하나의 속성 만 변경되었으므로 중복 된 항목이 많습니다.

모두 연속적인 행을 동일한 값으로 제거해야합니다.

예. 이전 테이블은 변환 표는

(order by time,type)   (order by type,time) 
time stn type value   time stn type value 
100 7 1  red   100 7 1 red 
100 7 2  large   101 7 1 red 
101 7 1  red   102 7 1 blue 
101 7 2  small   103 7 1 red 
102 7 1  blue   100 7 2 large 
102 7 2  small   101 7 2 small 
103 7 1  red   102 7 2 small 
103 7 2  small   103 7 2 small 

time stn type value 
100 7 1  red 
100 7 2  large 
101 7 2  small 
102 7 1  blue 
103 7 1  red 

표는 약 22 만명 행이 포함로 변경해야합니다입니다

time stn prop1 prop2 
100 7  red large 
101 7  red small 
102 7  blue small 
103 7  red small 

같은 값이 포함되어 있습니다.

내 현재의 접근 방식은 중복을 테이블을 반복하고 제거하는 절차를 사용하는 것입니다

BEGIN 
    DECLARE done INT DEFAULT FALSE; 
    DECLARE id INT; 
    DECLARE psid,nsid INT DEFAULT null; 
    DECLARE ptype,ntype INT DEFAULT null; 
    DECLARE pvalue,nvalue VARCHAR(50) DEFAULT null; 
    DECLARE cur CURSOR FOR 
     SELECT station_property_id,station_id,property_type,value 
     FROM station_property 
     ORDER BY station_id,property_type,gpstime; 
    DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE; 
    OPEN cur; 
    read_loop: LOOP 
     FETCH cur INTO id,nsid,ntype,nvalue; 
     IF done THEN 
      LEAVE read_loop; 
     END IF;   
     IF (psid = nsid and ptype = ntype and pvalue = nvalue) THEN 
      delete from station_property where station_property_id=id; 
     END IF; 
     SET psid = nsid; 
     SET ptype = ntype; 
     SET pvalue = nvalue; 
    END LOOP; 
    CLOSE cur; 
END 

그러나, 그것은 너무 느립니다. 20000 개의 행이있는 테스트 테이블에서 6 분 동안 10000 개의 중복을 제거합니다. 절차를 최적화하는 방법이 있습니까?

P. 나는 여전히 내 오래된 테이블을 그대로 가지고 있기 때문에 변환 후에 중복을 다루지 않고 복제없이 변환하는 것이 더 나을지도 모른다.

업데이트.

허용하고 싶은 복제본을 명확히하기 위해.

  1. 속성이 변경된 경우 다시 변경됩니다. 첫 번째와 마지막 station_id, type 및 value가 같지만 3 개의 레코드가 모두 저장되기를 원합니다.
  2. station_id, type 및 value가 동일한 여러 GPSTIME 레코드가있는 경우 첫 번째 레코드 (해당 값의 변경을 나타내는) 만 저장하면됩니다.

즉, a -> b -> b -> a -> aa -> b -> a으로 최적화되어야합니다.

솔루션

@Kickstart가 제안한 것처럼, 내가 필터링 된 데이터로 채워 새 테이블을 만들었습니다. 이전 행을 참조하려면 this question에 사용 된 것과 비슷한 접근 방식을 사용했습니다.

rename table station_property to station_property_old; 
create table station_property like station_property_old; 

set @lastsid=-1; 
set @lasttype=-1; 
set @lastvalue=''; 

INSERT INTO station_property(station_id,gpstime,property_type,value) 
select newsid as station_id,gpstime,newtype as type,newvalue as value from 
-- this subquery adds columns with previous values 
    (select station_property_id,gpstime,@lastsid as lastsid,@lastsid:=station_id as newsid, 
    @lasttype as lasttype,@lasttype:=property_type as newtype, 
    @lastvalue as lastvalue,@lastvalue:=value as newvalue 
    from station_property_old 
    order by newsid,newtype,gpstime) sub 
-- we filter the data, removing unnecessary duplicates 
where lastvalue != newvalue or lastsid != newsid or lasttype != newtype; 

drop table station_property_old; 
+0

결과 (중복되지 않은) 데이터 세트에서 '103 7 1 red'가 나타나는 이유는 무엇입니까? –

+0

@BrankoDimitrijevic 예제에 데이터를 추가했습니다. 시간 = 102에서 prop1이 "red"에서 "blue"로 변경되었습니다. 시간 = 103 prop1이 다시 변경되었습니다. 두 가지 변경 사항을 모두 테이블에 반영하고 싶습니다. 내가 원하지 않는 것은 큰 테이블을 "폭발"시켰을 때 추가 된 '103 7 2 small'과 같은 변경 사항을 나타내지 않는 레코드입니다. – aimozg

+0

@BrankoDimitrijevic는'(type, time)'에 의해 정렬 된 테이블을 보았습니다. 행을 삭제해야하는 것이 더 명확합니다. – aimozg

답변

1

GROUP BY를 사용하여 기존 테이블의 select로 채워진 새 테이블을 만들 가능성이 있습니다.이런 식으로 뭔가 (그래서 테스트되지는 오타 변명) : -

INSERT INTO station_property_new 
SELECT station_property_id, station_id, property_type, value 
FROM (SELECT station_property_id, station_id, property_type, value, COUNT(*) FROM station_property GROUP BY station_property_id, station_id, property_type, value) Sub1 
+0

너는 본다, 나는 ** 유일한 ** 역/유형/가치 조합을 다만 필요로하지 않는다 본다. 속성이 변경되고 다시 변경되면 해당 솔루션은 첫 번째 값의 레코드 하나만 저장합니다. 이 요구 사항을 반영하도록 예제를 업데이트하겠습니다. – aimozg

+0

중복을 선택하는 쿼리를 만들었습니다 :'select * from station_property p1 where p1.value = (hive.station_property p2의 값을 선택하십시오. 여기서 p2.property_type = p1.property_type 및 p2.gpstime> p1.gpstime by p2.gpstime 한계 1); '이지만 프로 시저보다 느립니다. – aimozg

+0

고유 한 시간, stn, 유형, 값을 원하지만 최신 gpstime을 원한다고 생각합니까? – Kickstart

1

chainging 특성에 관해서는, 당신은 역/형/값 컬럼의 조합 고유을 보장하기 위해 고유 제한 조건을 넣어 기운 다. 그렇게하면 중복을 초래할 수있는 값으로 변경할 수 없게됩니다.

+0

아니, 할 수 없다. 스테이션/유형/값의 조합은 고유하지 않아도됩니다. "업데이트"단락을 참조하십시오. – aimozg