2014-03-04 175 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」領域。