ON和WHERE子句的位置和效率表现

时间:2018-03-27 02:29:42

标签: sql postgresql performance inner-join

我有两个表,一个名为 Health_User ,另一个名为 Diary 。它们分别具有用户的人口统计信息和记录值。我想要做的是检索记录的值,但是:

  1. 使用 Health_User 中的“is_tester”列(布尔值)排除测试人员(非真实用户),
  2. Diary 中排除测量值过高或过低的不合理值。
  3. 所以我有几个查询应该得到相同的结果:

    # 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: Diary 的条件限制更复杂(请参阅查询1中的最后一个WHERE子句)。是否最好在JOIN内切换日记,并在查询3之外点击 Health_User ,否则没有区别?

    问题3:在性能方面是否有更好的解决方案?

1 个答案:

答案 0 :(得分:0)

如果数据库按照您的查询建议的顺序执行查询(首先过滤,然后加入,反之亦然),则会有所不同。

实际上,PostgreSQL有一个查询优化器,可以重新排列查询以找到最有效的执行顺序,并且所有查询最终都会使用相同的执行计划 ,您可以使用SQL语句EXPLAIN验证。

对于内连接,如果在连接之前或之后进行过滤,则不会影响结果;您也可以将所有条件写入连接条件而不更改结果。优化器知道这一点。

您可以通过创建适当的索引来加快执行速度。它取决于数据的分布,以了解某个索引是否有用。经验法则是选择条件下的索引(过滤掉许多数据)更有用。使用EXPLAIN查找最佳索引。