索引用于'外部'和内心的'嵌套选择中的where子句?

时间:2018-05-19 14:13:55

标签: sql postgresql select indexing

需要在选择条件的地方使用列别名。 找到了可能的解决方案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的相应idex(仅举例)。

如果此查询与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:是否存在性能问题?

2 个答案:

答案 0 :(得分:5)

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

以下查询将生成 flat 计划(且索引不相关)

\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的片段中,最里面的查询(表表达式)是一个双表连接 ,但机制是相同的:所有外层都可以剥离(并重命名结果列)

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

答案 1 :(得分:3)

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

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

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