Супер медленный запрос ... Что я сделал не так? - PullRequest
3 голосов
/ 17 декабря 2010

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

Во-первых, у меня есть таблица контактов, в которой хранятся клиенты моей компании.В таблице находится столбец 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

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

Чтобы все исправить, я убрал все «dbo».префиксы, которые добавляет 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.

НО, если я сделаю запрос с ЛЕВЫМИ ВНЕШНИМИ СОЕДИНЕНИЯМИ, как указано выше, я думаю, что у меня будет много людей с неправильными JobTitles, просто потому, что любой, у кого нет ИМЕНИ JobTitle ИЛИ JobFunction, будет в моем списке - они могутбыть «высокопоставленным руководителем» без JobFunction, и они будут в списке - что не правильно.У нас больше нет услуг, подходящих для «руководителей высшего звена».

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

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

Спасибо,

Рассел Шутте

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

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

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

Спасибо!

Рассел Шутте

Ответы [ 3 ]

6 голосов
/ 17 декабря 2010

Переместите запросы в ваших 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, чтобы привести простой пример.

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

0 голосов
/ 17 декабря 2010

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

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

0 голосов
/ 17 декабря 2010

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

...