我有一个包含大量记录的人员表(大约1600万),并要求找到所有人lastname
,首字母为firstname
和{{1} },在其他世界中,我想展示假设UI中的重复人员,供用户分析和决定是否有同一个人。
这是我写的查询
birthyear
但由于我不是SQL专家,想知道,这样做的好方法是什么?有更优化的方式吗?
修改
请注意,我可以剪切数据,这可能会对优化做出贡献
例如,如果我想将数据减少2,则可以返回两个人
SELECT *
FROM Person INNER JOIN
(
SELECT SUBSTRING(firstName, 1, 1) firstNameF,lastName,YEAR(birthDate) birthYear
FROM Person
GROUP BY SUBSTRING(firstName, 1,1),lastName,YEAR(birthDate)
HAVING count(*) > 1
) as dupPersons
ON SUBSTRING(Person.firstName,1,1) = dupPersons.firstNameF and Person.lastName = dupPersons.lastName and YEAR(Person.birthDate) = dupPersons.birthYear
order by Person.lastName,Person.firstName
答案 0 :(得分:2)
如果使用GROUP BY
的效果不足,您可以尝试使用INNER JOIN
SELECT *
FROM Person p1
INNER JOIN Person p2 ON p2.PersonID > p1.PersonID
WHERE SUBSTRING(p2.Firstname, 1, 1) = SUBSTRING(p1.Firstname, 1, 1)
AND p2.LastName = p1.LastName
AND YEAR(p2.BirthDate) = YEAR(p1.BirthDate)
ORDER BY
p1.LastName, p1.FirstName
答案 1 :(得分:2)
好吧,如果你不是专家,你写的查询告诉我你至少非常称职。当我们查看查询是否是“优化的”时,有两个直接的部分:1。查询本身有一些特别错误 - 一个错误的连接,关键字滥用,爆炸结果集大小,关于{的替代{1}}等2.查询在其中运行的上下文 - 数据库细节,任务细节等
您的查询通过#1,没问题。我会以不同的方式编写它 - 别名为Person表,使用NOT IN
而不是LEFT(P.FirstName, 1)
,并使用CTE(SUBSTRING
- 子句)而不是子查询。但这些都不是优化问题。如果结果对脏读不敏感,也许我会使用WITH
。在任何进一步的背景下,您的查询看起来不像是等待灭火的炸弹。
至于#2 - 您应该切换到细节。就像“我必须每周运行一次。这需要17分钟。我怎么能把它降到一分钟之内?”然后人们会问你的计划是什么样的,你有什么索引等等。
我想知道的事情:
示例场景:如果这是一个run-on-command功能,它将无限期地在我的应用程序中,它将每周运行,预计会有10%或更少的记录重复,能够更改数据库的方式我想,如果重复的匹配标准是坚定的(没有波动),并且我想将它从90s减少到5s,我会创建一个专用的WITH(READUNCOMMITTED)
列(可能是{{1}的持久计算列}})和BirthYear
上的索引。如果这些规定有太多变化,我可能会完全朝着不同的方向发展。
答案 2 :(得分:1)
你可以尝试这样的事情,看看执行计划的不同,或者根据绩效对结果进行基准测试:
;WITH DupPersons AS
(
SELECT *, COUNT(1) OVER(PARTITION BY SUBSTRING(firstName, 1, 1), lastName, YEAR(birthDate)) Quant
FROM Person
)
SELECT *
FROM DupPersons
WHERE Quant > 1
当然,了解您的表定义和您创建的索引也会有所帮助。我想也许它可以帮助添加一个带有birthdate年份的计算列并在其上创建一个索引,与firstname的第一个字母相同。