如何快速自我加入(与众不同)?

时间:2018-07-19 03:38:44

标签: sql database postgresql indexing query-optimization

我有一个如下表:

student_score
  id          int
  student_id  int
  score       int
  type        int
  is_repeat   boolean
  created_at  int

假设我想获取类型<10的学生的最新考试成绩,并且is_repeat等于false,所以我有这样的观点:

CREATE VIEW view_latest_student_score
AS
SELECT
  s1.*
FROM student_score s1
LEFT JOIN student_score s2
  ON s1.student_id = s2.student_id
  AND s2.type < 10
  AND s2.is_repeat = FALSE
  AND s1.id < s2.id
WHERE s1.type < 10
  AND s1.is_repeat = FALSE
  AND s2.id IS NULL;

那么如何为这种视图创建索引?目前,我在student_id上有索引(id是pk)。这种自我加入是否有一些最佳实践?

有时,我将使用列分数或类型查询类似此视图的视图。那么我应该添加诸如(student_id,score)或(score,student_id)的索引吗?

2 个答案:

答案 0 :(得分:0)

is_repeat + type上创建多列索引(列的顺序很重要)。
可以使用它来满足针对s表的这一条件,以使用索引范围扫描过滤掉某些行:

WHERE s1.type < 10
  AND s1.is_repeat = FALSE

可能被使用-但不一定必须使用-它取决于查询的选择性,当WHERE条件选择的值大于5时,数据库可能更喜欢全表扫描而不是使用此索引表中约10%的行):


为此联接条件在student_id列上也创建第二个索引:

 ON s1.student_id = s2.student_id
  AND s2.type < 10
  AND s2.is_repeat = FALSE
  AND s1.id < s2.id

对于这种情况,您也可以考虑在以下位置创建student_id + is_repeat + type(按此列的特定顺序)上的多列索引,但是我猜测student_id上的索引就足够了。

答案 1 :(得分:0)

由于只处理类型<10并且is_repeat = FALSE的行,因此部分索引就足够了。 (在部分索引中,WHERE条件可以将索引行限制为类型<10并且is_repeat = FALSE的那些行,因此优化程序不需要查找这些行)。

CREATE INDEX idx_test ON student_score 
    (student_id, score, type, is_repeat, created_at) 
WHERE TYPE < 10 AND is_repeat = FALSE