【问题标题】:Is index used for 'outer' and 'inner' where clauses in nested selects?索引是否用于嵌套选择中的“外部”和“内部”where 子句?
【发布时间】:2018-10-29 18:35:35
【问题描述】:

需要在 where 条件中使用列别名进行选择。 找到了可能的解决方案here

假设我们有一对一的关系(用户到角色),我们希望得到如下结果:

SELECT u.name AS u_name, r.name AS r_name
FROM users AS u
  INNER JOIN roles AS r
    ON u.role_id = r.role_id
WHERE u.name = 'John'

我们有user.name 的对应索引(仅作为示例)。

如果使用EXPLAIN 运行此查询,它将显示选择期间使用的所有索引(包括名称索引)。

现在,由于我们想在 WHERE 子句中使用别名,因此我们可以根据建议的解决方案重写查询:

SELECT * FROM (
  SELECT u.name AS u_name, r.name AS r_name
  FROM users AS u
    INNER JOIN roles AS r
      ON u.role_id = r.role_id
) AS temp
WHERE u_name = 'John'

如您所见,嵌套选择中没有WHERE 子句。使用EXPLAIN 运行此查询会得到相同的结果(只是承认,我不是分析“解释”结果的专家,但仍然):

  • 相同的索引
  • 同样的费用
  • 类似的执行时间

我对这个结果有点困惑:确信至少不会使用用户名的索引。

Q1: postgres 是否以这种方式使用索引?

Q2:是否存在性能问题?

【问题讨论】:

  • 优化器可以重写查询,从而找到解决问题的更好方法。通常它会做正确的事,您无需担心。

标签: sql postgresql select indexing


【解决方案1】:

不需要子查询,因此可以展开/折叠。

以下查询将生成一个平面计划(与索引无关)


\i tmp.sql

CREATE TABLE t
        (a integer not null primary key
        );

insert into t(a)
select v from generate_series(1,10000) v
        ;

ANALYZE t;

EXPLAIN
SELECT * from (
        select d AS e from (
                select c as d from (
                        select b AS c from (
                                select a AS b from t
                                        ) s
                                ) r
                        ) q
                ) p
where e =95
        ;

结果计划:


DROP SCHEMA
CREATE SCHEMA
SET
CREATE TABLE
INSERT 0 10000
ANALYZE
                             QUERY PLAN                              
---------------------------------------------------------------------
 Index Only Scan using t_pkey on t  (cost=0.17..2.38 rows=1 width=4)
   Index Cond: (a = 95)
(2 rows)

在OP的片段中,最里面的查询(表表达式)是一个两表连接 ,但机制是一样的:所有外层都可以剥离(结果列重命名)

是的:连接将受益于连接字段上的索引,最终 where 也可以使用索引。

【讨论】:

    【解决方案2】:

    SQL 是一种描述性 语言,而不是一种过程 语言。 SQL 查询描述正在生成的结果集。它没有指定如何创建它——在没有编译器选项或提示的 Postgres 中更是如此。

    实际运行的是一个有向无环操作图 (DAG)。编译步骤创建 DAG。 Postgres 很聪明地意识到子查询是没有意义的,所以两个版本都针对同一个 DAG 进行了优化。

    让我补充一点,我认为 Postgres 通常会实现 CTE,因此使用 CTE 可能会阻止使用索引。

    【讨论】:

    • [注意:此处不涉及 CTE](在 Postgres 中)CTE总是具体化,因为它保证只执行一次。
    • Postgresql always 实现 CTE,尽管希望改变它(至少在需要时)。
    • @LaurenzAlbe 。 . .或者也许使用编译器选项? ;) 我知道那是一场宗教战争。
    猜你喜欢
    • 2023-03-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-11-01
    • 2011-01-01
    相关资源
    最近更新 更多