2014-03-04 131 views
0

我正在尝试找出一种更有效的方式来编写我公司使用的查询。目前我们正在使用LEFT JOIN,但我觉得这可能是一个不好的方法来解决这个问题。使用JOIN优化查询

你们都会怎么做?我正在尝试熟悉EXISTS和CROSS APPLY。也许这是我应该使用这些类型的语句的情况。

SELECT p.people_id , 
     p.date_created , 
     p.last_name , 
     p.first_name , 
     p.middle_name , 
     p.known_as , 
     p.ssn , 
     p.home_phone , 
     p.work_mobile , 
     p.other_phone , 
     p.display_email , 
     s.source , 
     ISNULL(p.address_1, '') AS address_1 , 
     ISNULL(p.address_2, '') AS address_2 , 
     p.city , 
     p.state , 
     p.zip_code , 
     pec.emergency_name , 
     pec.work_phone , 
     pec.emergency_relationship , 
     jc.job_category , 
     et.education_type , 
     pp.part_time_only , 
     pp.perm_job , 
     pp.temp_job , 
     p.applied_online , 
     p.owner_division_id , 
     p.role_id , 
     p.older_18 , 
     p.disclaimer , 
     SUBSTRING(p.ssn, 6, 4) AS L4_ssn , 
     pp.custom_code_4 AS job_title , 
     p.external_id , 
     p.last4 , 
     p.resume_category , 
     rc.resume_category_description , 
     p.home_phone_perm , 
     p.work_mobile_perm 
FROM people p 
     LEFT OUTER JOIN lkp_resume_category rc ON p.resume_category = rc.resume_category_id 
     LEFT OUTER JOIN people_profile pp ON pp.people_id = p.people_id 
     LEFT OUTER JOIN companies_job_titles cjt ON cjt.job_title_id = pp.job_title_1 
     LEFT OUTER JOIN lkp_job_categories jc ON jc.job_category_id = pp.job_class_id 
     LEFT OUTER JOIN lkp_education_types et ON et.education_type_id = pp.education_id 
     LEFT OUTER JOIN lkp_sources s ON pp.source_id = s.source_id 
     LEFT OUTER JOIN people_emergency_contacts pec ON p.people_id = pec.people_id 
WHERE (p.role_id <= 4) 

Results Plan Diagram

+0

看起来不像“INNER JOINs”。但看着执行计划,你应该考虑索引你的表。 – Magnus

+0

我输错了那个。谢谢你指出。 – HKImpact

回答

3

实际上有被问这里两个独立的问题:

  1. 我应该使用LEFT JOIN的?
  2. 如何让我的查询更高效?

我会先回答#2,因为我认为这很容易。在您的查询计划中,超过70%的成本来自“人员”表的表扫描。因此,您可以整天优化您的JOIN,但仍不会提高效率。关键的问题是,你的“人员”中有多少比例的“角色ID < = 4”?如果它低于10%,根据您的索引方式,您可以进行优化;如果它超过70% - 也就是说,如果这个查询的目的实际上是拉出“人物”表中所有人的近乎完整的列表 - 那么你几乎必须支付这样做的成本。

现在,关于问题1:只要以下关于您的数据模型的推论是真实的,那么您的左连接可能是您尝试做的最好的方法。推论如下:

  1. “人物”条目具有零对应的对应简历类别;也就是说,people.resume_category_id可以为NULL或可以具有有意义的值。 (如果在父表中没有找到无效值,那么您将遇到参照完整性问题,并且您需要的是外键约束。)
  2. “人员”条目具有零对多紧急联系人。
  3. “人员”条目具有零至多人的个人档案。
  4. A“的个人配置文件”项具有零到一的职称(如上面resume_category)
  5. A“的个人配置文件”项具有零到一的工作类别(如上)
  6. A“的人(如上所述)
  7. “人物档案”条目具有零对一的来源(如上所述)
  8. 您想列出所有人,无论是否存在或不存在数据在这些其他表中的任何一个

希望帮助和所有b美东时间。

---编辑---

嘿,事情一直困扰着我这个答案,我刚才想通了,它是什么。您的查询结构存在实际问题,但与使用LEFT JOIN无关。这是你一次加入到两个不同的子表,两者都有相同的“人”父表。根据数据的实际分布情况,这将为您提供笛卡尔产品作为结果集。例如,假设您有一个具有两个配置文件(“工作”和“主页”)和两个紧急联系人(“Alice”和“Carol”)的人“Bob”。然后,结构像你这样的查询将给予:

Person Profile Contact 
------ ------- ------- 
Bob  Work  Alice 
Bob  Home  Alice 
Bob  Work  Carol 
Bob  Home  Carol 

如果是结构类似于零一对多的关系可以,其实有多个子行,那么解决方案取决于您的应用程序如何使用数据。有,但是,两个基本可能的方法:

  1. 独立每个零一对多连接成自己的查询,所以你一共有三个查询而不是一个。
  2. 使用某种类型的聚合运算符,如FIRST或MAX(稍微粗略一点,因为它可以在结果集中给出不可预知的结果和/或混合和匹配字段)。

作为一个侧面说明,如果孩子表不能有多个子行,那么你应该确保这一点通过把唯一约束到每个这些表中的“people_id”领域。