2013-10-24 5 views
1

매우 큰 테이블 (2 억 행)가 일치
다음 sID INT, wordID INT (PK sid를 wordID)찾기 정확한 FK는

하는 SID가의있는 것을 찾으려는 동일한 wordID의 (없이 엑스트라) SID를 들어
는 그것을 제한 할 아래로 너무 기꺼이 간다와 정확히 일치의 기회를 wordID 100 이상 100
(이 학교이고 SID를 클래스와 wordID 인 경우 만

) 1000에 가고 싶다 학생들이었습니다.
다음으로 나는 똑같은 학생을 가진 수업을 찾고 싶습니다.

시드,
1,1-
1,2
1,3-
2,2
2,3
3,1
3,4-
5, wordID 1
5 2
6
2 6 3 7
1
7,2 01,238,007 31,627,552,314,960,453,210 8, 1
8, 1

다음 sID 6과 2는 동일한 wordID의
다음 sID 5, 7, 그리고 8은 동일한 wordID의이

이것은 내가 지금까지
이 무엇을 가지고 나는이 삭제 # temp3_sID1_sID2을 제거하고
위의 삽입에 그 처리를 싶습니다하지만 당신이 쉽게

와 테스트 200 만 개 행이있는 테이블을 만들 수 있습니다처럼되지 않습니다
어떤 아이디어를 시도 할 것이다
drop table #temp_sID_wordCount 
    drop table #temp_count_wordID_sID 
    drop table #temp3_wordID_sID_forThatCount 
    drop table #temp3_sID1_sID2 
    drop table #temp3_sID1_sID2_keep 
    create table #temp_sID_wordCount (sID int primary key, ccount int not null) 
    create table #temp_count_wordID_sID (ccount int not null, wordID int not null, sID int not null, primary key (ccount, wordID, sID)) 
    create table #temp3_wordID_sID_forThatCount (wordID int not null, sID int not null, primary key(wordID, sID)) 
    create table #temp3_sID1_sID2_keep (sID1 int not null, sID2 int not null, primary key(sID1, sID2)) 
    create table #temp3_sID1_sID2 (sID1 int not null, sID2 int not null, primary key(sID1, sID2)) 
    insert into #temp_sID_wordCount 
    select sID, count(*) as ccount 
    FROM [FTSindexWordOnce] with (nolock) 
    group by sID 
    order by sID; 
    select count(*) from #temp_sID_wordCount where ccount <= 100; -- 701,966 
    truncate table #temp_count_wordID_sID 
    insert into #temp_count_wordID_sID 
    select #temp_sID_wordCount.ccount, [FTSindexWordOnce].wordID, [FTSindexWordOnce].sID 
    from #temp_sID_wordCount 
    join [FTSindexWordOnce] with (nolock) 
     on [FTSindexWordOnce].sID = #temp_sID_wordCount.sID 
    and ccount >= 1 and ccount <= 10 
    order by #temp_sID_wordCount.ccount, [FTSindexWordOnce].wordID, [FTSindexWordOnce].sID; 
    select count(*) from #temp_sID_wordCount; -- 34,860,090 

    truncate table #temp3_sID1_sID2_keep 
    declare cur cursor for 
    select top 10 ccount from #temp_count_wordID_sID group by ccount order by ccount 

    open cur 
    declare @count int, @sIDcur int 
    fetch next from cur into @count 
    while (@@FETCH_STATUS = 0) 
    begin 
     --print (@count) 
     --select count(*), @count from #temp_sID_wordCount where #temp_sID_wordCount.ccount = @count 
     truncate table #temp3_wordID_sID_forThatCount 
     truncate table #temp3_sID1_sID2 

     -- wordID and sID for that unique word count 
     -- they can only be exact if they have the same word count 
     insert into #temp3_wordID_sID_forThatCount 
     select  #temp_count_wordID_sID.wordID 
       , #temp_count_wordID_sID.sID 
     from #temp_count_wordID_sID 
     where #temp_count_wordID_sID.ccount = @count 
     order by #temp_count_wordID_sID.wordID, #temp_count_wordID_sID.sID 

     -- select count(*) from #temp3_wordID_sID_forThatCount 

     -- this has some duplicates 
     -- sID1 is the group 
     insert into #temp3_sID1_sID2 
     select w1.sID, w2.sID 
     from #temp3_wordID_sID_forThatCount as w1 with (nolock) 
     join #temp3_wordID_sID_forThatCount as w2 with (nolock) 
      on w1.wordID = w2.wordID 
     and w1.sID <= w2.sID   
     group by w1.sID, w2.sID 
     having count(*) = @count 
     order by w1.sID, w2.sID 

     -- get rid of the goups of 1  
     delete #temp3_sID1_sID2 
     where sID1 in (select sID1 from #temp3_sID1_sID2 group by sID1 having count(*) = 1) 

     -- get rid of the double dips   
     delete #temp3_sID1_sID2 
     where #temp3_sID1_sID2.sID1 in 
       (select distinct s1del.sID1 -- these are the double dips 
       from #temp3_sID1_sID2 as s1base with (nolock) 
       join #temp3_sID1_sID2 as s1del with (nolock) 
        on s1del.sID1 > s1base.sID1 
       and s1Del.sID1 = s1base.sID2) 

     insert into #temp3_sID1_sID2_keep  
     select #temp3_sID1_sID2.sID1 
      , #temp3_sID1_sID2.sID2 
     from #temp3_sID1_sID2 with (nolock) 
     order by #temp3_sID1_sID2.sID1, #temp3_sID1_sID2.sID2 

    fetch next from cur into @count 
    end 
    close cur 
    deallocate cur 

select * 
FROM #temp3_sID1_sID2_keep with (nolock) 
order by 1,2 

답변

1

그래서 내가 보는 것처럼, 작업은 동일한 하위 집합을 찾는 것입니다.

;with tmp1 as (select sID, cnt = count(wordID) from [Table] group by sID) 
select s1.sID, s2.sID 
from tmp1 s1 
    cross join tmp1 s2 
    cross apply (
     select count(1) 
     from [Table] d1 
      join [Table] d2 on d2.wordID = d1.wordID 
     where d1.sID = s1.sID and d2.sID = s2.sID 
    ) c(cnt) 
where s1.cnt = s2.cnt 
    and s1.sID > s2.sID 
    and s1.cnt = c.cnt 

출력은 다음과 같습니다 :

sID  sID 
----------- ----------- 
6   2 
7   5 
8   5 
8   7 

그리고 쌍 그룹으로 결합 할 수 있습니다, 필요한 경우 :

먼저 우리는 동일한 부분 집합의 쌍을 찾을 수 있습니다

sID   gNum 
----------- ----------- 
2   1 
6   1 
5   2 
7   2 
8   2 

참조 아래 SqlFiddle 샘플의 세부 정보

SqlFiddle Sample


다른 방법은 모든 서브 세트 데이터에 해시 함수를 계산하는 것이다

;with a as (
    select distinct sID from [Table] 
) 
select sID, 
    hashbytes('sha1', (
     select cast(wordID as varchar(10)) + '|' 
     from [Table] 
     where sID = a.sID 
     order by wordID 
     for xml path(''))) 
from a 

이어서 서브 세트가 해시 값에 기초하여 그룹화 될 수있다.

SqlFiddle Sample

마지막

약 10 백만 행 (20K SID를 wordID 각을 1k로 최대 값)의 테스트 데이터를 내 컴퓨터에서 분 미만했다. 또한 단어 ID 개수 일치가없는 sID를 다른 규칙과 제외하여 최적화 할 수도 있습니다.

+0

예제 데이터에서는 작동하지만 큰 테이블에서는 7 시간 내에 완료되지 않아 확인할 수 없습니다. – Paparazzi

+0

@Blam, 다른 접근 방식을 추가했습니다. 업데이트 된 답변을 참조하십시오. –

+0

굉장한 접근법이지만 약간의 문제가 있습니다. 600 단어의 최대 단어 수 또는 문자열 또는 이진 데이터 잘린 된 오류가 얻을 갈 필요가있다. 그리고 해시 바이트를 꺼내면 XML 용이므로 오류가 발생합니다. 그러나 한계는 600 분으로 2 분이 채 안 걸렸습니다. – Paparazzi

관련 문제