Используется ли индекс для «внешних» и «внутренних», где предложения во вложенных выборках? - PullRequest
0 голосов
/ 19 мая 2018

Столкнулся с необходимостью использования псевдонимов столбцов, где условие для выбора.Найденное возможное решение здесь .

Предположим, у нас есть отношение один-к-одному (пользователь-роль), и мы хотим получить следующие результаты:

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'

И у нас есть соответствующий idex для 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: Возможны ли проблемы с производительностью?

Ответы [ 2 ]

0 голосов
/ 19 мая 2018

Подзапрос не нужен, поэтому его можно развернуть / свернуть.

Следующий запрос сгенерирует план 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 самый внутренний запрос (табличное выражение) является соединением из двух таблиц, но механизмто же самое: все внешние слои могут быть отделены (и столбец результатов переименован)

И да: объединение получит выгоду от индексов на соединенных полях, а финальный - где можетиспользуйте индекс тоже.

0 голосов
/ 19 мая 2018

SQL является описательным языком, а не процедурным языком.Запрос SQL описывает создаваемый набор результатов.В нем не указано, как его создать, и это тем более верно в Postgres, у которого нет опций компилятора или подсказок.

На самом деле запускается ациклический граф операций (DAG).На этапе компиляции создается DAG.Postgres достаточно умен, чтобы понять, что подзапрос не имеет смысла, поэтому две версии оптимизированы для одного и того же DAG.

Позвольте мне добавить, что я думаю, что Postgres обычно материализует CTE, поэтому использование CTE может помешать индексу бытьб.

...