Супер медленный запрос... Что я сделал не так?

Вы, ребята, потрясающие. За последние пару дней я дважды писал здесь - новый пользователь - и я был просто потрясен помощью. Итак, я решил, что возьму самый медленный запрос, который у меня есть в моем программном обеспечении, и посмотрим, сможет ли кто-нибудь помочь мне ускорить его. Я использую этот запрос в качестве представления, поэтому важно, чтобы он был быстрым (и это не так!).

Во-первых, у меня есть таблица контактов, в которой хранятся клиенты моей компании. В таблице находится столбец JobTitle, который содержит идентификатор, определенный в таблице Contacts_Def_JobFunctions. Существует также таблица с именем contacts_link_job_functions, в которой хранится номер идентификатора контакта и дополнительные функции работы, которые есть у клиента - также определенные в таблице Contacts_Def_JobFunctions.

Во-вторых, записи таблицы Contacts_Def_JobFunctions имеют отношения родитель / потомок между собой. Таким образом, мы группируем похожие функции работы (например, горничная, услуги прачечной, уборка, уборка и т. Д. - это одна и та же базовая работа, хотя название должности может меняться). Рабочие функции, с которыми мы в настоящее время не работаем, поддерживаются как дочерние элементы ParentJobID 1841.

В-третьих, учреждения с дополнительными кодами просто предоставляют географические данные до конечного результата.

Наконец, как и все ответственные компании, мы ведем список удаления для всех наших клиентов, которые хотят отказаться от нашей рассылки (после выбора).

Я использую следующий запрос, чтобы составить таблицу из тех людей, которые подписались на нашу новостную рассылку и у которых есть должность или должность, относящаяся к услугам / продуктам, которые мы предлагаем.

Вот мой уродливый запрос:

SELECT DISTINCT 
    dbo.contacts_link_emails.Email, dbo.contacts.ContactID, dbo.contacts.First AS ContactFirstName, dbo.contacts.Last AS ContactLastName, dbo.contacts.InstitutionID, 
    dbo.institutionswithzipcodesadditional.CountyID, dbo.institutionswithzipcodesadditional.StateID, dbo.institutionswithzipcodesadditional.DistrictID
FROM         
    dbo.contacts_def_jobfunctions AS contacts_def_jobfunctions_3 
INNER JOIN
    dbo.contacts 
INNER JOIN
    dbo.contacts_link_emails 
        ON dbo.contacts.ContactID = dbo.contacts_link_emails.ContactID 
        ON contacts_def_jobfunctions_3.JobID = dbo.contacts.JobTitle 
INNER JOIN
    dbo.institutionswithzipcodesadditional 
        ON dbo.contacts.InstitutionID = dbo.institutionswithzipcodesadditional.InstitutionID 
LEFT OUTER JOIN
    dbo.contacts_def_jobfunctions 
INNER JOIN
    dbo.contacts_link_jobfunctions 
        ON dbo.contacts_def_jobfunctions.JobID = dbo.contacts_link_jobfunctions.JobID 
        ON dbo.contacts.ContactID = dbo.contacts_link_jobfunctions.ContactID
WHERE     
        (dbo.contacts.JobTitle IN
        (SELECT     JobID
        FROM          dbo.contacts_def_jobfunctions AS contacts_def_jobfunctions_1
        WHERE      (ParentJobID <> '1841'))) 
    AND
        (dbo.contacts_link_emails.Email NOT IN
        (SELECT     EmailAddress
        FROM          dbo.newsletterremovelist)) 
OR
        (dbo.contacts_link_jobfunctions.JobID IN
        (SELECT     JobID
        FROM          dbo.contacts_def_jobfunctions AS contacts_def_jobfunctions_2
        WHERE      (ParentJobID <> '1841')))
    AND 
        (dbo.contacts_link_emails.Email NOT IN
        (SELECT     EmailAddress
        FROM          dbo.newsletterremovelist AS newsletterremovelist)) 

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

Спасибо,

Рассел Шутте

ОБНОВЛЕНИЕ - ОБНОВЛЕНИЕ - ОБНОВЛЕНИЕ - ОБНОВЛЕНИЕ - ОБНОВЛЕНИЕ

После получения нескольких сообщений обратной связи, особенно от Ханзора, я усердно работал над настройкой этого запроса и получил следующее:

SELECT  DISTINCT
                  contacts_link_emails.Email, contacts.ContactID, contacts.First AS ContactFirstName, contacts.Last AS ContactLastName, contacts.InstitutionID, 
                  institutionswithzipcodesadditional.CountyID, institutionswithzipcodesadditional.StateID, institutionswithzipcodesadditional.DistrictID
FROM contacts 
INNER JOIN
    contacts_def_jobfunctions ON contacts.jobtitle = contacts_def_jobfunctions.JobID AND contacts_def_jobfunctions.ParentJobID <> '1841'
INNER JOIN
    contacts_link_jobfunctions ON contacts_link_jobfunctions.JobID = contacts_def_jobfunctions.JobID AND contacts_def_jobfunctions.ParentJobID <> '1841'
INNER JOIN
    contacts_link_emails ON contacts.ContactID = contacts_link_emails.ContactID 
INNER JOIN
    institutionswithzipcodesadditional ON contacts.InstitutionID =  institutionswithzipcodesadditional.InstitutionID
LEFT JOIN
    newsletterremovelist ON newsletterremovelist.emailaddress = contacts_link_emails.email
WHERE    
    newsletterremovelist.emailaddress IS NULL

Это не совсем идеально (я подозреваю, что я должен был сделать что-то внешнее или правильное, или что-то в этом роде, и я не совсем уверен). Мой набор результатов составляет около 40% записей, предоставленных моим исходным запросом (что я уже не на 100% уверен, что это был идеальный запрос).

Чтобы навести порядок, я вынул все "дбо". префиксы, которые добавляет SQL Studio. Они что-нибудь делают?

Что я делаю не так сейчас?

Спасибо,

Рассел Шутте

== == == == == == ДРУГОЕ ОБНОВЛЕНИЕ == ДРУГОЕ ОБНОВЛЕНИЕ == ДРУГОЕ ОБНОВЛЕНИЕ == ДРУГОЕ ОБНОВЛЕНИЕ == ДРУГОЕ ОБНОВЛЕНИЕ == == == == ==

Я работал над этим одним запросом уже несколько часов. Я дошел до этого:

SELECT DISTINCT 
                      contacts_link_emails.Email, contacts.contactID,  contacts.First AS ContactFirstName, contacts.Last AS ContactLastName, contacts.InstitutionID, 
                      institutionswithzipcodesadditional.CountyID, institutionswithzipcodesadditional.StateID, institutionswithzipcodesadditional.DistrictID
FROM         
    contacts INNER JOIN institutionswithzipcodesadditional
        ON contacts.InstitutionID = institutionswithzipcodesadditional.InstitutionID
    INNER JOIN contacts_link_emails 
        ON contacts.ContactID = contacts_link_emails.ContactID
    LEFT OUTER JOIN contacts_def_jobfunctions 
        ON contacts.JobTitle = contacts_def_jobfunctions.JobID AND contacts_def_jobfunctions.ParentJobID <> '1841'
    LEFT OUTER JOIN contacts_link_jobfunctions
        ON contacts_link_jobfunctions.JobID = contacts_def_jobfunctions.JobID AND contacts_def_jobfunctions.ParentJobID <> '1841' 
    LEFT OUTER JOIN
        newsletterremovelist ON newsletterremovelist.EmailAddress = contacts_link_emails.Email
WHERE     (newsletterremovelist.EmailAddress IS NULL)

К сожалению, я просто не могу заполнить пробелы в моих знаниях. Я новичок в объединениях, за исключением случаев, когда у меня есть визуальный инструмент, создающий их для меня, поэтому я думаю, что хочу все: от контактов, учреждений с дополнительными кодами и контактов_link_emails, поэтому я ВНУТРИ СОЕДИНИТЬ их (см. Выше).

Я озадачен следующим битом. Если я присоединяюсь к ним ВНУТРЕННИМ, то я найду людей, у которых есть подходящая работа (<> 1841) - но я думаю, что Я ПОТЕРЯЮСЬ на людях, у которых нет записи для JobTitle И JobFunctions. Во многих случаях это не правильно. Я мог бы иметь JobTitle "Хранитель", который я хотел бы сохранить в нашем списке рассылки, но если у него также нет записи JobFunction, я думаю, что он исчезнет из списка, если я использую INNER JOIN.

НО, если я сделаю запрос с LEFT OUTER JOINs, как указано выше, я думаю, что я получу много людей с неправильными JobTitles, просто потому, что любой, кому не хватает EITHER JobTitle ИЛИ JobFunction, будет в моем списке - они могут быть "High Level Executive"без JobFunction, и они будут в списке - что не правильно. У нас больше нет услуг, подходящих для руководителей высшего звена.

Затем я вижу, как LEFT OUTER JOIN работает для рассылки новостей. Это довольно гладко, и я думаю, что сделал все правильно...

Но я все еще застрял. Надеюсь, кто-нибудь увидит, что я пытаюсь сделать здесь, и направит меня в правильном направлении.

Спасибо,

Рассел Шутте

ОБНОВЛЕНИЕ СНОВА

К сожалению, эта тема, кажется, умерла, без идеального решения - но я уже близко. Пожалуйста, посмотрите новую тему, которая возобновляет обсуждение: нажмите здесь

(присуждается правильный ответ за огромный объем предоставленной работы - даже если правильный ответ не совсем достигнут).

Спасибо!

Рассел Шутте

3 ответа

Решение

Переместите запросы в свой WHERE к фактическим соединениям. Они называются коррелированными подзапросами и являются работой Волдеморта. Если они являются объединениями, они выполняются только один раз и ускорят ваш запрос.

Для NOT IN разделы, используйте левое внешнее соединение и убедитесь, что столбец, к которому вы присоединились, NULL,

Кроме того, избегайте использования OR в WHERE запросы, где это возможно - помните, что OR не обязательно операция короткого замыкания.

Пример таков:

SELECT 
    *
FROM
    dbo.contacts AS c
INNER JOIN
    dbo.contacts_def_jobfunctions AS jf
    ON c.JobTitle = jf.JobId AND jf.ParentJobID <> '1841'
INNER JOIN
    dbo.contacts_link_emails AS e
    ON c.ContactID = e.ContactID AND jf.JobID = c.JobTitle 
LEFT JOIN
    dbo.newsletterremovelist AS rl
    ON e.Email = rl.EmailAddress
WHERE    
    rl.EmailAddress IS NULL

Пожалуйста, не используйте это, так как это почти наверняка неправильно (не говоря уже о SELECT *), Я проигнорировал логику для contacts_ref_jobfunctions_3, чтобы предоставить простой пример.

Для (действительно) хорошего объяснения объединений, попробуйте это визуальное объяснение объединений

Создайте несколько представлений, представляющих некоторые общие ассоциации, которые вы делаете, чтобы ваш подзапрос был проще. Также представления выполняются немного быстрее, так как их не нужно интерпретировать при каждом запуске.

Это может быть любое количество вещей. Мой первый вопрос: индексируются ли столбцы, к которым вы присоединяетесь?

А еще лучше сделать SHOWPLAN и вставьте его в свой вопрос.

Другие вопросы по тегам