超慢查询...我做错了什么?

时间:2010-12-16 22:36:40

标签: sql join unique distinct

你们很棒。在过去的几天里,我已经在这里发布了两次 - 一个新用户 - 我被帮助感到震惊。所以,我想我会在我的软件中查看最慢的查询,看看是否有人可以帮助我加快速度。我将此查询用作视图,因此快速(并且它不是!)非常重要。

首先,我有一个存储我公司客户的联系人表。在表中是一个JobTitle列,其中包含在Contacts_Def_JobFunctions表中定义的ID。还有一个名为contacts_link_job_functions的表,它保存了客户所拥有的contactID号和其他工作职能 - 也在Contacts_Def_JobFunctions表中定义。

其次,Contacts_Def_JobFunctions表记录与他们自己有父/子关系。通过这种方式,我们将类似的工作职能集中在一起(例如:女仆,洗衣服务,家务管理,清洁等都是相同的基本工作 - 而职称可能会有所不同)。我们目前不使用的工作职能是作为ParentJobID 1841的子女维护的。

第三,使用zipcodes附加的机构只是为最终结果提供地理数据。

最后,与所有负责任的公司一样,我们为希望选择退出简报的任何客户(选择加入后)保留一份删除列表。

我使用以下查询构建一个表格,其中列出了那些选择接收我们的简报并且具有与我们提供的服务/产品相关的职位或职位的人员。

这是我的UGLY查询:

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)) 

我希望你们中的一些超级明星可以帮我调整一下。

非常感谢,

Russell Schutte

UPDATE - UPDATE - UPDATE - UPDATE - UPDATE

在收到几条反馈信息后,特别是来自Khanzor,我一直在努力调整此查询并提出以下建议:

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%肯定是一个完美的查询)。

为了清理,我拿出了所有的“dbo”。 SQL Studio添加的前缀。他们做了什么吗?

我现在做错了什么?

谢谢,

Russell Schutte

== == == == == ==另一个更新==另一个更新==另一个更新==另一个更新==另一个更新 == == == == ==

我已经在这个问题上工作了好几个小时了。我已经明白了这一点:

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)

令人失望的是,我只是无法填补我的知识空白。我是新手加入的,除非我有可视化工具为我构建它们,所以我想我想要的东西来自联系人,机构,zipcodesadditional和contacts_link_emails,所以我已经INNER加入了他们(上图)。

我对下一点感到难过。如果我INNER加入他们,那么我会找到有适当工作的人(&lt;&gt; 1841) - 但我想我会失去那些没有JobTitle和JobFunctions条目的人。在许多情况下,这是不对的。我可以有一个JobTitle“Custodian”,我想留在我们的新闻通讯列表中,但如果他还没有JobFunction条目,我认为如果我使用INNER JOIN,他将不在列表中。

但是,如果我使用LEFT OUTER JOIN进行查询,如上所述,我认为我有很多人使用错误的JobTitles,只是因为任何缺少JobTitle或JobFunction的人都会出现在我的列表中 - 他们可以成为一名没有JobFunction的“高级管理人员”,他们会出现在名单上 - 这是不对的。我们不再提供适合“高级管理人员”的服务。

然后我看到LEFT OUTER JOIN如何为newsletterremovelist工作。这很光滑,我想我做得对...

但我仍然被卡住了。希望有人可以看到我在这里想要做的事情并引导我朝着正确的方向前进。

谢谢,

Russell Schutte

再次更新

可悲的是,这个线程似乎已经死了,没有一个完美的解决方案 - 但我已经接近了。请参阅已启动的新线程,重新开始讨论:click here

(为所提供的大量工作给出了正确的答案 - 即使没有达到正确的答案)。

谢谢!

Russell Schutte

3 个答案:

答案 0 :(得分:6)

WHERE中的查询移至实际联接。这些被称为相关子查询,是Voldemort的工作。如果它们是连接,它们只执行一次,并且会加快查询速度。

对于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的逻辑提供一个简单的例子。

有关联接的(非常)好的解释,请尝试this visual explanation of joins

答案 1 :(得分:0)

创建一些视图,表示您创建的一些常见关联,以便您的子查询更简单。此外,视图执行速度更快,因为每次运行时都不需要对它们进行解释。

答案 2 :(得分:0)

它可以是任何数量的东西。我的第一个问题是您加入索引的列?

更好的是,做一个SHOWPLAN并将其粘贴到您的问题中。