我可以使这个T-SQL代码更有效

时间:2011-01-27 10:09:51

标签: sql-server tsql

我在一个包含300万条比较电子邮件地址的记录的表上运行SQL查询。

我们有两个电子邮件地址字段,主要和次要。

我正在将主要电子邮件的子集与所有其他主要和次要电子邮件进行比较,以计算数据中的重复项和唯一电子邮件的数量。

我相信这个代码有效,它仍然运行10分钟,我必须为另外9个子集做这个,这个子集比这个要大很多。代码如下:

SELECT COUNT(*) AS UniqueRecords
FROM AllVRContacts 
WHERE LEN(EMAIL) > 1 AND ACCOUNTID = '00120000003bNmMAAU'

AND EMAIL NOT IN
(SELECT EMAIL FROM AllVRContacts WHERE ACCOUNTID != '00120000003bNmMAAU')

AND EMAIL NOT IN
(SELECT SECONDARY_EMAIL_ADDRESS__C FROM AllVRContacts WHERE ACCOUNTID != '00120000003bNmMAAU')

我想从中学到一些东西,而不仅仅是有人为我刮伤我的背,越多的解释越好!

谢谢你们,

4 个答案:

答案 0 :(得分:2)

创建以下索引:

AllVrContacts (AccountID) INCLUDE (Email)
AllVrContacts (Email) INCLUDE (AccountID)
AllVrContacts (SECONDARY_EMAIL_ADDRESS__C) INCLUDE (AccountID)

(AccountID, Email)上的索引将用于主查询中的WHERE过滤器:

WHERE  ACCOUNTID = '00120000003bNmMAAU'
       AND LEN(Email) > 1

其他两个索引将用于针对此表的反连接(NOT IN)。

您还应该使用:

SELECT COUNT(DISTINCT email) AS UniqueRecords

如果您希望同一帐户中的重复项只计算一次。

答案 1 :(得分:1)

SELECT COUNT(*)
FROM   (SELECT EMAIL AS UniqueRecords
        FROM   AllVRContacts a
        WHERE  ACCOUNTID = '00120000003bNmMAAU'
               AND NOT EXISTS (SELECT EMAIL FROM AllVRContacts b
                               WHERE ACCOUNTID != '00120000003bNmMAAU'
                                     AND (
                                          a.EMAIL = b.EMAIL
                                          OR a.EMAIL = b.SECONDARY_EMAIL_ADDRESS__C
                                     )
               )
               AND LEN(EMAIL) > 1
        GROUP  BY EMAIL
) c

那么这个查询怎么更好?

  1. 您通常希望使用NOT EXISTS而不是NOT IN

    如果指定的值与子查询或列表中的任何值匹配,则

    IN返回true

    如果子查询包含任何行

    ,则

    EXISTS返回true

    更多信息:SQL Server: JOIN vs IN vs EXISTS - the logical difference

  2. =比!=

  3. 表现更好
  4. 通过不再通过AllVRContacts搜索辅助电子邮件比较来减少扫描(寻找在AllVRContacts上有索引)

  5. GROUP BY解决了ACCOUNTID内潜在的重复电子邮件

  6. 为了进一步提高性能,按照Quassnoi的建议添加索引,填充表格的任何内容都应该验证电子邮件,以消除对LEN检查的需要。

    [编辑]向(3)

    添加了解释

答案 2 :(得分:1)

这可以适用吗?

SELECT ACCOUNTID, COUNT(*) AS UniqueRecords
FROM (
  SELECT ACCOUNTID, EMAIL
  FROM AllVRContacts
  WHERE ACCOUNTID = '00120000003bNmMAAU' AND LEN(EMAIL) > 1
  UNION
  SELECT ACCOUNTID, SECONDARY_EMAIL_ADDRESS__C
  FROM AllVRContacts
  WHERE ACCOUNTID = '00120000003bNmMAAU' AND LEN(SECONDARY_EMAIL_ADDRESS__C) > 1
) s

据我所知,基本上你想为每个ACCOUNTID计算不同的电子邮件地址。

内部查询中的UNION消除了重复项,因此(内部查询的)输出只有不同的帐户ID和电子邮件对,无论是主要还是次要。特别是这意味着如果电子邮件地址同时存储为主要和次要,它将只计数一次。同样适用于存储在不同行中的相同主要或相同的辅助地址。

现在你只需要计算行数,这是由外部查询完成的。

如果您提到的其他9个子集仅指其他ACCOUNTID,那么您可以尝试将GROUP BY ACCOUNTID应用于外部查询,并且ACCOUNTID = '...'两个WHERE部分的SELECT ACCOUNTID, COUNT(*) AS UniqueRecords FROM ( SELECT ACCOUNTID, EMAIL FROM AllVRContacts WHERE LEN(EMAIL) > 1 UNION SELECT ACCOUNTID, SECONDARY_EMAIL_ADDRESS__C FROM AllVRContacts WHERE LEN(SECONDARY_EMAIL_ADDRESS__C) > 1 ) s GROUP BY ACCOUNTID 部分都可以删除使用一个查询计算所有这些邮件的电子邮件。就是这样:

{{1}}

答案 3 :(得分:0)

试试这个并告诉我

SELECT ACCOUNTID,COUNT(*)AS UniqueRecords 来自AllVRContacts
LERE(EMAIL)> 1 AND ACCOUNTID ='00120000003bNmMAAU'
由ACCOUNTID集团 有COUNT(EMAIL)> 1