2014-10-07 309 views
3

見下面的查詢避免嵌套循環

Select count(*) FROM 
(Select distinct Student_ID, Name, Student_Age, CourseID from student) a1 
JOIN 
(Select distinct CourseID, CourseName, TeacherID from courses) a2 
ON a1.CourseID=a2.CourseID 
JOIN 
(Select distinct TeacherID, TeacherName, Teacher_Age from teachers) a3 
ON a2.TeacherID=a3.TeacherID 

的子查詢必須用於重複數據刪除的目的。

這個查詢在PostgreSQL中運行良好。但是,如果我在學生表和老師表之間添加了一個條件,根據執行計劃,Postgres會錯誤地嵌套循環連接學生並教授沒有直接關係的表。例如:

Select count(*) FROM 
(Select distinct Student_ID, Name, Student_Age, CourseID from student) a1 
JOIN 
(Select distinct CourseID, CourseName, TeacherID from courses) a2 
ON a1.CourseID=a2.CourseID 
JOIN 
(Select distinct TeacherID, TeacherName, Teacher_Age from teachers) a3 ON 
a2.TeacherID=a3.TeacherID 
WHERE Teacher_Age>=Student_Age 

此查詢將永遠運行。但是,如果我用表替換子查詢,它將運行得非常快。如果不使用臨時表來存儲重複數據刪除結果,有沒有辦法在這種情況下避免嵌套循環?

謝謝你的幫助。

+2

爲什麼要在加入表格本身時加入內嵌查詢?考慮一下,做一個LEFT JOIN,把條件放在join子句中而不是WHERE。 – Rahul 2014-10-07 19:09:48

+0

子查詢必須用於重複數據刪除。我們的數據集中有很多。上面的每張表格都包含大約3M的記錄。 – toanong 2014-10-07 19:11:49

+0

如果你在學生,教師和課程表中有很多重複,這聽起來像是你的模式中的一個缺陷。唯一標識屬性應該在一個表中,並且無論數據與它們相關,並且在選擇標識數據時導致重複項應該位於一個或多個其他表中。 – gwaigh 2014-10-08 03:59:01

回答

0

您正在使數據庫執行大量不必要的工作來實現您的目標。不要將3個不同的SELECT DISTINCT子查詢連接在一起,而是嘗試將基表直接相互連接,並讓它只處理一次DISTINCT部分。如果你的表在ID字段中有適當的索引,這應該運行得相當快。

SELECT COUNT(1) 
    FROM (
    SELECT DISTINCT s.Student_ID, c.CourseID, t.TeacherID 
     FROM student s 
     JOIN courses c ON s.CourseID = c.CourseID 
     JOIN teachers t ON c.TeacherID = t.TeacherID 
     WHERE t.Teacher_Age >= s.StudentAge 
    ) a