Могу ли я сделать этот код T-SQL более эффективным - PullRequest
1 голос
/ 27 января 2011

Я выполняю SQL-запрос к таблице, содержащей 3 миллиона записей, сравнивающих адреса электронной почты.

У нас есть два поля адреса электронной почты: основное и дополнительное.

Я сравниваю подмножество первичных электронных писем со всеми другими первичными и вторичными электронными письмами, чтобы получить количество дубликатов и уникальных электронных писем в данных.

Я считаю, что этот код работает, он все еще работает 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 ]

2 голосов
/ 27 января 2011

Создайте следующие индексы:

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 голос
/ 27 января 2011

Может ли это быть применимо?

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 во внутреннем запросе устраняет дубликаты, поэтому выходные данные (внутреннего запроса) содержат только отдельные пары идентификаторов учетных записей и электронных писем, будь то первичные или вторичные. В частности, это означает, что если адрес электронной почты хранится как основной, так и дополнительный, он будет учитываться только один раз. То же относится и к одному и тому же первичному или одинаковому вторичному адресу, хранящемуся в разных строках.

Теперь вам нужно только посчитать строки, что делается внешним запросом.

Если другие 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 голос
/ 27 января 2011
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: соединение против IN против EXISTS - логическая разница

  2. = работает намного лучше, чем! =

  3. Сократите количество сканирований (ищет, если у вас есть индексы на AllVRContacts), не просматривая AllVRContacts второй раз для сравнения вторичных электронных писем

  4. GROUP BY устраняет возможные дубликаты электронных писем в ACCOUNTID

Чтобы еще больше повысить производительность, добавьте индексы, как предложил Quassnoi, и все, что заполняет таблицу, должно проверять электронную почту, чтобы устранить необходимость проверки LEN.

[EDIT] Добавлено пояснение к (3)

0 голосов
/ 27 января 2011

Попробуйте и дайте мне знать

ВЫБЕРИТЕ ACCOUNTID, COUNT (*) AS UniqueRecords ОТ AllVRContacts
ГДЕ LEN (EMAIL)> 1 И ACCOUNTID = '001200003bNmMAAU'
Сгруппировать по ACCOUNTID Имея COUNT(EMAIL)> 1

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...