2014-10-07 143 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