我们有一个庞大的公司表(1700万条目),我们希望根据搜索条件(基于电话号码)查找重复项。查询运行速度很慢(5分钟+)
以下是查询的简化版本,但问题是相同的:
SELECT C1.*
FROM dbo.Company AS C1 WITH(NOLOCK)
INNER JOIN dbo.Company AS C2 ON C2.sTelephone = C1.sTelephone
AND C1.iId_company != C2.iId_company
AND (C1.iId_third_party_id IS NULL OR
C2.iId_third_party_id IS NULL)
列说明:
我们拥有相同电话号码但主键不同(重复)的公司是什么,还有一部分没有第三方ID(告诉我们最终用户插入了它。
现在,我尝试了一些东西,但没有给我任何线索:
我最终让UNION将两个查询组合在一起(每个查询都在 OR 条件下),但我想了解为什么在使用 OR 在这种情况下。
答案 0 :(得分:2)
找出性能差异的最佳方法是检查您尝试过的查询的执行计划。他们可以提供很多信息。不幸的是,我不是SQL Server专家,所以我不知道如何获得执行计划。
答案 1 :(得分:2)
我不知道这在性能方面是否有任何帮助(因为我手头没有17mio。行表来测试),但是这个怎么样:
由于您使用的是SQL Server 2008,因此您应该可以创建类似这样的内容(公用表表达式 - CTE)。这应该会缩小搜索范围,因为只有(希望!)公司表中的少数条目确实会重复 - 所以这应该限制你的搜索速度,从而加快搜索速度(或者至少是希望!)。
WITH PhoneDuplicates AS
(SELECT c.Telephone, COUNT(*) as PhoneCount
FROM dbo.Company AS c
GROUP BY c.Telephone
HAVING COUNT(*) > 1
)
SELECT
(list of fields from company table)
FROM
dbo.Company AS c
INNER JOIN
PhoneDuplicates as PD ON PD.Telephone = c.Telephone
马克
答案 2 :(得分:1)
性能方面,过滤列的基数是什么?
也许只有
C1.iId_third_party_id IS NULL
提升了性能,因为SQL可以告诉(根据索引构建的统计信息)相对较少的行符合必要的标准。当你添加
(... OR C2.iId_third_party_id IS NULL)
也许SQL认为结果连接会产生如此多的匹配行,因此在该列上使用索引效率不高。
同样,有多少匹配/重复的电话号码? 如果这种情况非常罕见,我会做类似marc_s的查询(他打败了我),因为它会飞。
很大程度上取决于数据的样子 - 您的过滤条件出现的频率或频率。分析一下,尝试并了解它是如何以及它如何随时间变化,并相应地设计您的查询。
答案 3 :(得分:1)
删除OR部分时看到的速度增加是因为OR自动执行索引扫描而不是搜索。通过将它们结合在一起,你可以做更快的2次寻找。
尝试使用row_number技术找到欺骗:
;with cteDupes(RN, DupeID, DupeTelephone) as
(
SELECT row_number() over(partition by sTelephone order by iId_company, sTelephone) RN,
iId_company, sTelephone
FROM dbo.Company
WHERE iId_third_party_id IS NULL
)
select * from cteDupes
where RN > 1
这将只返回被欺骗的行。 这样做的好处是你只能获得一张桌子而不是两张。
答案 4 :(得分:0)
你可以尝试的东西是
SELECT C1.*
FROM (select * from dbo.Company where iId_third_party_id IS NULL) AS C1 WITH(NOLOCK)
INNER JOIN (select * from dbo.Company where iId_third_party_id IS NULL) AS C2 ON C2.sTelephone = C1.sTelephone
AND C1.iId_company != C2.iId_company
因为这对我们有所帮助。
答案 5 :(得分:0)
我怀疑你的非聚集索引是否会被使用(sTelephone
,iId_third_party_id
)。您是否在主键上进行聚类?
查看估计的执行计划。
在没有看到计划的情况下,我会考虑将iId_third_party_id
添加到sTelephone
上的非聚集索引,如果您没有在主键上进行聚类,则添加iId_company
也是索引。
请注意,当给定电话号码的重复次数超过两次时,结果可能会出现交叉连接倍增。
答案 6 :(得分:0)
With Temp as
(Select *
FROM dbo.Company as c
Where c.iId_third_party_id is NULL)
Select C1.*
From temp as C1 With (NoLock)
INNER JOIN Temp AS C2
ON C2.sTelephone = C1.sTelephone AND C1.iId_company != C2.iId_company
这样的事情可能会起作用