如何在具有大量记录的表中优化组

时间:2011-02-10 11:54:57

标签: sql sql-server-2008

我有一个包含大量记录的人员表(大约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

3 个答案:

答案 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分钟。我怎么能把它降到一分钟之内?”然后人们会问你的计划是什么样的,你有什么索引等等。

我想知道的事情:

  • 运行需要多长时间?
  • 你的运行时窗口是什么? (查询时间的用户和应用程序容差。)
  • 这是每天运行一次吗?周?月?季度?
  • 您是否有权创建表,更改当前表或更改索引?
  • 也许基于运行它,您期望找到的重复项的比例是多少? 5%? 90%?
  • 匹配标准要求的稳定性如何?

示例场景:如果这是一个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的第一个字母相同。