2014-01-12 78 views
0

我有一個數據庫存儲有關虛構人物的各種信息。有一個人的一般信息,如姓名,地址等,以及一些更具體的表格,爲每個人提供健康史和教育。 我現在想要做的是,基於相同的時間在同一所學校或同一個醫生或在同一醫院同時接受治療的相似之處,讓一個人獲得可能的聯繫。轉換SQL在哪裏加入

以下查詢對此工作正常(:id是有問題的人的id),但它非常慢(大約需要6secs才能得到結果)。

SELECT person.p_id as id, fname, lname, image FROM person WHERE 
       (person.p_id IN (
        SELECT patient from health_case WHERE 
         doctor IN (SELECT doctor FROM health_case WHERE patient =:id) 
         OR center IN (SELECT hc2.center FROM health_case as hc1, health_case as hc2 WHERE hc1.patient = :id AND hc2.center = hc1.center AND (hc1.start <= hc2.end AND hc1.end >= hc2.start))) 
       OR person.p_id IN (
        SELECT ed2.pupil FROM education as ed1, education as ed2 WHERE 
         ed1.school IN (SELECT school FROM education WHERE pupil = :id) AND ed2.school = ed1.school AND (ed2.start <= ed1.end AND ed2.end >= ed1.start) 
       )) 
       AND person.p_id != :id 

將其轉換爲使用JOIN子句的最佳方法是什麼?我似乎無法將我的頭圍繞在這些...

回答

2

我想我明白你想要做什麼。有不止一種方式來剝皮貓,但我可以建議將查詢拆分爲兩個單獨的查詢,然後用幾個內部聯接替換複雜的WHERE子句?所以,這樣的事情:

/* Find connections based on health care */ 
SELECT p2.p_id as id, p2.fname, p2.lname, p2.image 
FROM person p 
JOIN health_case hc on hc.patient = p.p_id 
JOIN health_case hc2 on hc2.doctor = hc.doctor and hc2.healthcenter = hc.healthcenter and hc.start <= hc2.end and hc.end >= hc2.start and hc2.patient <> hc.patient 
JOIN person p2 on p2.p_id = hc2.patient and p2.p_id <> p.p_id 
WHERE p.p_id = :id 

然後,創建一個單獨的查詢基於教育獲得連接:

/* Find connections based on education */ 
SELECT p2.p_id as id, p2.fname, p2.lname, p2.image 
FROM person p 
JOIN education e on e.pupil = p.p_id 
JOIN education e2 on e2.school = e.school and e2.start <= e.end AND e2.end >= e.start and e.pupil <> e2.pupil 
JOIN person p2 on p2.p_id = e2.pupil and p2.p_id <> p.p_id 
WHERE p.p_id = :id 

如果你真的想要的數據結果相結合,可以使用UNION因爲兩個查詢返回人員表中的相同列。

+0

這應該可行,而且很好,但要小心,在即將考慮重構架構之前,您將達到大多數人推薦的連接數的限制。 – Zarathuztra

+0

感謝您對模式結構的建議@Z! – Scott

+0

經過一段時間的測試後,我認爲這有效,而且速度也非常快。無論如何分割查詢無疑是一個好主意,可以將可能的連接分類。 – powlomat

0

取決於您的SQL引擎。具有合理查詢優化器的新SQL系統很可能會將IN和JOIN查詢重寫爲同一個計劃。通常,使用聯接來重寫子查詢(IN子句)。

在簡單的SQL引擎中,可能沒有很好的查詢優化器,因此連接速度應該更快,因爲它們可能會在運行外部查詢之前將子查詢運行到臨時內存表中。

但是,在一些有限內存佔用的SQL引擎中,子查詢可能會更快,因爲它不需要連接 - 這會產生更多數據。