我有两张桌子,一张叫健康用户,另一张叫日记。它们分别有用户的人口统计信息和记录值。我想做的是检索记录的值,但是:
不包括Health用户中“is_tester”列(布尔值)的测试人员(非实际用户),以及
排除日记中测量值过高或过低的不合理值。
所以我有几个问题应该得到相同的结果:

# Query 1
SELECT d.user_id, d.id AS diary_id, d.glucose_value, d.unit
    FROM Diary AS d
    JOIN (
        SELECT id
        FROM Health_User
        WHERE is_tester = false
    ) AS u
    ON d.user_id = u.id
    WHERE ((d.glucose_value >= 20 AND d.glucose_value <= 600 AND d.unit = 'mg/dL')
            OR (d.glucose_value >= 20/18.02 AND d.glucose_value <= 600/18.02 AND d.unit = 'mmol/L'));

# Query 2
SELECT d.user_id, d.id AS diary_id, d.glucose_value, d.unit
    FROM Diary AS d
    JOIN Health_User AS u
    ON d.user_id = u.id
    WHERE u.is_tester = false
        AND ((d.glucose_value >= 20 AND d.glucose_value <= 600 AND d.unit = 'mg/dL')
              OR (d.glucose_value >= 20/18.02 AND d.glucose_value <= 600/18.02 AND d.unit = 'mmol/L'));

# Query 3
SELECT d.user_id, d.id AS diary_id, d.glucose_value, d.unit
    FROM Health_User AS u
    JOIN (
        SELECT id, user_id, glucose_value, unit
        FROM Diary
        WHERE ((glucose_value >= 20 AND glucose_value <= 600 AND unit = 'mg/dL')
                OR (glucose_value >= 20/18.02 AND glucose_value <= 600/18.02 AND unit = 'mmol/L'))
    ) AS d
    ON d.user_id = u.id
    WHERE u.is_tester = false;

我有三个问题:
问题1:我推测查询1的性能会比查询2好,因为a)它只连接一列而不是整个Health_User表,b)它在连接表之前过滤掉测试人员。我说的对吗?
问题2:日记的条件限制更为复杂(参见查询1中的最后一个WHERE子句)。最好在JOIN内切换日志,让Health_用户像查询3一样在外部,还是没有区别?
问题3:在性能方面还有更好的解决方案吗?

最佳答案

如果数据库按照查询建议的顺序执行查询(首先筛选,然后连接,反之亦然),则会有差异。
事实上,PostgreSQL有一个查询优化器,它可以重新排列查询以找到最有效的执行顺序,并且所有查询都将以相同的执行计划结束,您可以使用SQL语句EXPLAIN对其进行验证。
对于内部联接,如果在联接之前或之后进行筛选,则不会影响结果;还可以将所有条件写入联接条件,而不更改结果。优化器知道这一点。
您可以通过创建适当的索引来加快执行速度。要知道某个索引是否有用,取决于数据的分布。经验法则是,选择性条件(过滤掉许多数据)上的索引更有用。与EXPLAIN一起寻找最佳索引。

关于sql - ON和WHERE子句的位置以及效率表现,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/49503484/

10-11 19:56