【问题标题】:Postgres: Optimize QueryPostgres:优化查询
【发布时间】:2022-01-24 06:41:21
【问题描述】:

我有一种情况,我需要显示已发布学习材料或测试的科目列表。 下面的查询有效,但大约需要 8 秒。有没有更好的方法可以优化此查询? 谢谢。

SELECT sj.*, sj.id AS id FROM subjects sj 
WHERE ( 
    (SELECT COUNT(lmc.id) FROM learning_materials_codes lmc 
    INNER JOIN students s ON lmc.student_id = s.id 
    INNER JOIN learning_materials lm ON lmc.learning_material_id = lm.id 
    WHERE lmc.student_id = 1 AND sj.id = ANY(lm.subject_ids)) > 0 
        OR 
    (SELECT COUNT(tc.id) FROM test_codes tc 
    INNER JOIN students s ON tc.student_id = s.id 
    INNER JOIN tests t ON tc.test_id = t.id 
    WHERE tc.student_id = 1 AND t.subject_id = sj.id) > 0 
)
AND sj.school_id = 1
Table structure below

subjects
~~~~~~~~~~~
id
name
school_id
...

students
~~~~~~~~~~
id
f_name
l_name
school_id
...

tests
~~~~~~~~~
id
title
subject_id
...

test_codes
~~~~~~~~~~
test_id
student_id
code
...

learning_materials
~~~~~~~~~~~~~~~~~
id
title
subject_ids []
...

learning_material_codes
~~~~~~~~~~~~~~~~~~~~~~~~
learning_material_id
student_id
code
...

注意: 每次发布学习材料或测试时,都会为学生生成访问代码,并且该数据保存在 learning_material_codestest_codes 表中

【问题讨论】:

  • 请提供表格结构。
  • 为什么要加入学生?
  • 请显示 EXPLAIN (ANALYZE, BUFFERS)

标签: sql database postgresql


【解决方案1】:

我会将查询重写为

SELECT sj.*
FROM subjects sj 
WHERE EXISTS (SELECT 1
              FROM learning_materials_codes lmc 
                 INNER JOIN students s ON lmc.student_id = s.id
                 INNER JOIN learning_materials lm ON lmc.learning_material_id = lm.id
              WHERE lmc.student_id = 1
                AND sj.id = ANY(lm.subject_ids)
                AND lmc.id IS NOT NULL)
AND sj.school_id = 1
UNION
SELECT sj.*
FROM subjects sj 
WHERE EXISTS (SELECT 1
              FROM test_codes tc 
                 INNER JOIN students s ON tc.student_id = s.id 
                 INNER JOIN tests t ON tc.test_id = t.id 
              WHERE tc.student_id = 1
                AND t.subject_id = sj.id
                AND tc.id IS NOT NULL)
AND sj.school_id = 1;

这样,PostgreSQL 可以使用半连接并且可能更快。如果您不介意重复的结果行,请使用 UNION ALL 而不是 UNION 以获得更好的性能。

使用适当的索引可能会获得更多性能,但它需要EXPLAIN (ANALYZE, BUFFERS, VERBOSE, SETTINGS) 输出来评估。

【讨论】:

    猜你喜欢
    • 2011-02-13
    • 1970-01-01
    • 1970-01-01
    • 2015-09-13
    • 2021-08-31
    • 2017-12-25
    • 2021-05-04
    • 1970-01-01
    相关资源
    最近更新 更多