Супер медленный запрос... Что я сделал не так?
Вы, ребята, потрясающие. За последние пару дней я дважды писал здесь - новый пользователь - и я был просто потрясен помощью. Итак, я решил, что возьму самый медленный запрос, который у меня есть в моем программном обеспечении, и посмотрим, сможет ли кто-нибудь помочь мне ускорить его. Я использую этот запрос в качестве представления, поэтому важно, чтобы он был быстрым (и это не так!).
Во-первых, у меня есть таблица контактов, в которой хранятся клиенты моей компании. В таблице находится столбец 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
и вставьте его в свой вопрос.