Tsql 查找精确的FK匹配
拥有非常大的表(超过2亿行)Tsql 查找精确的FK匹配,tsql,sql-server-2008-r2,Tsql,Sql Server 2008 R2,拥有非常大的表(超过2亿行) sID int,wordID int(主键sID,wordID) 要查找具有完全相同wordID的sID(并且没有附加项) 对于一个ID超过100字的sID,精确匹配的几率会下降,因此愿意将其限制在100 (但我想去1000) 如果这是学校,sID是班级,wordID是学生。 然后我想找到学生完全相同的班级 sID,wordID 1,1 1,2 1,3 2,2 2,3 3,1 3,4 5,1 5,2 6,2 6,3 7,1 7,2 8,1 8,1 sID 6和2具有
sID int,wordID int(主键sID,wordID) 要查找具有完全相同wordID的sID(并且没有附加项)
对于一个ID超过100字的sID,精确匹配的几率会下降,因此愿意将其限制在100
(但我想去1000) 如果这是学校,sID是班级,wordID是学生。
然后我想找到学生完全相同的班级 sID,wordID
1,1
1,2
1,3
2,2
2,3
3,1
3,4
5,1
5,2
6,2
6,3
7,1
7,2
8,1
8,1 sID 6和2具有完全相同的wordID
sID 5、7和8具有完全相同的wordID 这就是我目前所拥有的
我想删除两个delete#temp3_sID1_sID2,并在上面的插入中处理它
但我会尝试任何想法
这不像您可以轻松创建一个包含2亿行的表来进行测试
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
drop table#temp_sID_wordCount
下拉表#临时(临时)计数(字ID)sID
将表格#temp3_wordID_sID_用于计数
升降台#temp3_sID1_sID2
升降台#临时3 sID1 sID2 keep
创建表#temp_sID_wordCount(sID int主键,ccount int非空)
创建表#temp#count#wordID#sID(ccount int not null,wordID int not null,sID int not null,主键(ccount,wordID,sID))
创建表#temp3_wordID_sID_forThatCount(wordID int不为null,sID int不为null,主键(wordID,sID))
创建表#temp3_sID1_sID2_keep(sID1 int不为null,sID2 int不为null,主键(sID1,sID2))
创建表#temp3_sID1_sID2(sID1 int不为null,sID2 int不为null,主键(sID1,sID2))
插入到#temp#u sID#u wordCount中
选择sID,将(*)计数为ccount
从[FTSindexWordOnce]到(nolock)
按sID分组
按sID排序;
从#temp_sID_wordCount中选择count(*),其中ccount=1和ccount,如我所见,任务是找到相等的子集
首先,我们可以找到一对相等的子集:
;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
请参阅下面SQLFIDLE示例中的详细信息
另一种方法是为每个子集数据计算哈希函数:
;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
然后可以根据散列值对子集进行分组
最后一个测试在我的机器上花费了不到一分钟的时间来获取大约1000万行的测试数据(每个测试数据行的sID值为20k,最高可达1k个wordID)。您还可以通过排除没有wordID计数匹配的SID来优化它。因此,正如我所见,任务是找到相等的子集
首先,我们可以找到一对相等的子集:
;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
请参阅下面SQLFIDLE示例中的详细信息
另一种方法是为每个子集数据计算哈希函数:
;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
然后可以根据散列值对子集进行分组
最后一个测试在我的机器上花费了不到一分钟的时间来获取大约1000万行的测试数据(每个测试数据行的sID值为20k,最高可达1k个wordID)。您还可以通过排除没有wordID计数匹配的SID来优化它。它可以处理示例数据,但在大表上,它没有在7小时内完成,因此我无法验证。这种方法很棒,但我有一个小问题。我需要去最大字数为600,否则我得到的字符串或二进制数据将被截断错误。如果我去掉hashbytes,我仍然会得到错误,因此它在for XML中。但在限制为600的情况下,它在不到两分钟的时间内运行。@Blam,我记得我遇到了这个问题,因为xml的一些内部限制已经存在,您可以尝试将SID分成50-200-500-1000k行的批。另外,hashbytes
输入限制为8000字节。所以,你可能需要把它的输入分成8k个部分,超过8k的部分,然后计算每个部分的哈希值和concat哈希值。实际上我可以在.NET中完成。这就是我在.NET中解析和加载的数据。它可以处理样本数据,但在大表上,它没有在7小时内完成,所以我无法验证。方法很棒,但我有一个小问题。我需要去最大字数为600,否则我得到的字符串或二进制数据将被截断错误。如果我去掉hashbytes,我仍然会得到错误,因此它在for XML中。但在限制为600的情况下,它在不到两分钟的时间内运行。@Blam,我记得我遇到了这个问题,因为xml的一些内部限制已经存在,您可以尝试将SID分成50-200-500-1000k行的批。另外,hashbytes
输入限制为8000字节。所以,你可能需要把它的输入分成8k个部分,超过8k的部分,然后计算每个部分的哈希值和concat哈希值。实际上我可以在.NET中完成。这就是我在.NET中解析和加载的数据。