【问题标题】:Avoid nested loop in PostgreSQL避免在 PostgreSQL 中使用嵌套循环
【发布时间】:2014-12-02 07:20:04
【问题描述】:

请参阅下面的查询

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

此查询将永远运行。但是,如果我用表替换子查询,它会运行得非常快。在不使用临时表存储去重结果的情况下,有没有办法避免这种情况下的嵌套循环?

感谢您的帮助。

【问题讨论】:

  • 既然可以加入表本身,为什么还要加入内联查询。考虑一下,改为执行 LEFT JOIN 并将条件放在 join 子句中而不是 WHERE。
  • 子查询必须用于重复数据删除。我们的数据集中有很多这样的东西。此外,上面的每个表都包含大约 3M 条记录。
  • 如果学生、教师和课程表中有很多重复,这听起来像是架构中的缺陷。唯一标识属性应位于一个表中,并且与它们相关的任何数据都应在您选择标识数据应位于一个或多个其他表中时导致重复。
  • 我们可以使用buffers 选项来制定您的计划吗?
  • @gwaigh:我无法更改架构或数据。这些表是多站点数据集成的结果。在每个站点,每个学生都是独一无二的。然而,由于同一学生的数据在集成后可能存储在多个站点,因此出现了重复。

标签: postgresql loops join nested subquery


【解决方案1】:

您正在使数据库执行大量不必要的工作来实现您的目标。不要将 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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-06-25
    • 2021-08-19
    • 2020-01-07
    • 1970-01-01
    • 2017-08-27
    • 2017-11-11
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多