Нужна помощь в понимании объяснения SQL запроса JOIN по сравнению с запросом с подвыборками - PullRequest
1 голос
/ 14 января 2011

Я разместил предыдущий вопрос здесь, спрашивая о том, что было лучше, JOIN запросов или запросов с использованием подвыборов.Ссылка: Запросы в запросах: есть ли лучший способ?

Это расширение к этому вопросу.Может кто-нибудь объяснить мне, почему я вижу то, что вижу здесь?

Запрос (Подвыборы):

SELECT article_seq, title, synopsis, body, lastmodified_date, (SELECT type_id FROM types WHERE kbarticles.type = type_seq), status, scope, images, archived, author, owner, (SELECT owner_description FROM owners WHERE kbarticles.owner = owner_seq),  (SELECT review_date FROM kbreview WHERE kbarticles.article_seq = article_seq) FROM kbarticles WHERE article_seq = $1

Объяснить Анализ (Подвыборы))

QUERY PLAN

Index Scan using article_seq_pkey on kbarticles  (cost=0.00..32.24 rows=1 width=1241) (actual time=1.421..1.426 rows=1 loops=1)

  Index Cond: (article_seq = 1511)

  SubPlan

    ->  Seq Scan on kbreview  (cost=0.00..14.54 rows=1 width=8) (actual time=0.243..1.158 rows=1 loops=1)

          Filter: ($2 = article_seq)

    ->  Seq Scan on owners  (cost=0.00..1.16 rows=1 width=24) (actual time=0.073..0.078 rows=1 loops=1)

          Filter: ($1 = owner_seq)

    ->  Index Scan using types_type_seq_key on types  (cost=0.00..8.27 rows=1 width=24) (actual time=0.044..0.050 rows=1 loops=1)

          Index Cond: ($0 = type_seq)

Total runtime: 2.051 ms

Запрос (JOIN с)

SELECT k.article_seq, k.title, k.synopsis, k.body, k.lastmodified_date, t.type_id, k.status, k.scope, k.images, k.archived, k.author, k.owner, o.owner_description, r.review_date FROM kbarticles k JOIN types t ON k.type = t.type_seq JOIN owners o ON k.owner = o.owner_seq JOIN kbreview r ON k.article_seq = r.article_seq WHERE k.article_seq = $1

Объяснить Анализ (JOIN с)

QUERY PLAN

Nested Loop  (cost=0.00..32.39 rows=1 width=1293) (actual time=0.532..1.467 rows=1 loops=1)

  Join Filter: (k.owner = o.owner_seq)

  ->  Nested Loop  (cost=0.00..31.10 rows=1 width=1269) (actual time=0.419..1.345 rows=1 loops=1)

        ->  Nested Loop  (cost=0.00..22.82 rows=1 width=1249) (actual time=0.361..1.277 rows=1 loops=1)

              ->  Index Scan using article_seq_pkey on kbarticles k  (cost=0.00..8.27 rows=1 width=1241) (actual time=0.065..0.071 rows=1 loops=1)

                    Index Cond: (article_seq = 1511)

              ->  Seq Scan on kbreview r  (cost=0.00..14.54 rows=1 width=12) (actual time=0.267..1.175 rows=1 loops=1)

                    Filter: (r.article_seq = 1511)

        ->  Index Scan using types_type_seq_key on types t  (cost=0.00..8.27 rows=1 width=28) (actual time=0.048..0.055 rows=1 loops=1)

              Index Cond: (t.type_seq = k.type)

  ->  Seq Scan on owners o  (cost=0.00..1.13 rows=13 width=28) (actual time=0.022..0.038 rows=13 loops=1)

Total runtime: 2.256 ms

Основываясь на ответах (и принятых) на мой предыдущий вопрос, JOIN s должны показать лучшие результаты.Однако во всех моих тестах JOIN с худшими результатами на несколько миллисекунд.Также кажется, что JOIN s пронизаны вложенными циклами.Все таблицы, которые я JOIN индексировал, индексируются.

Я делаю что-то, что я должен делать по-другому?Я что-то упускаю?

Ответы [ 3 ]

2 голосов
/ 14 января 2011

Эти запросы логически отличаются.

Первый:

SELECT  article_seq, title, synopsis, body, lastmodified_date,
        (
        SELECT  type_id
        FROM    types
        WHERE   kbarticles.type = type_seq
        ),
        status, scope, images, archived, author, owner,
        (
        SELECT  owner_description
        FROM    owners
        WHERE   kbarticles.owner = owner_seq
        ),
        (
        SELECT  review_date
        FROM    kbreview
        WHERE   kbarticles.article_seq = article_seq
        )
FROM    kbarticles
WHERE   article_seq = $1

Второй:

SELECT  k.article_seq, k.title, k.synopsis, k.body, k.lastmodified_date, t.type_id, k.status,
        k.scope, k.images, k.archived, k.author, k.owner, o.owner_description, r.review_date
FROM    kbarticles k
JOIN    types t
ON      k.type = t.type_seq
JOIN    owners o
ON      k.owner = o.owner_seq
JOIN    kbreview r
ON      k.article_seq = r.article_seq
WHERE   k.article_seq = $1

Если в * более одной записи1009 *, owners или kbreview, первый запрос не будет выполнен, а второй вернет дубликаты из kbarticles.

Если нет types, owners или kbreviews дляkbarticle, первый запрос вернет NULL в соответствующее поле, а второй просто пропустит эту запись.

Если поля *_seq кажутся полями PRIMARY KEY, тоникогда не будет дубликатами, и запрос никогда не потерпит неудачу;таким же образом, если kbarticles ограничен ссылками FOREIGN KEY на types, owners или kbreview, пропущенные строки не могут быть.

Однако операторы JOIN дают оптимизаторубольше места: он может сделать любую таблицу ведущей и использовать более продвинутые JOIN методы, такие как HASH JOIN или MERGE JOIN, которые недоступны, если вы используете подзапросы.

0 голосов
/ 14 января 2011

Учитывая, что оба плана выполняют одно и то же сканирование таблиц, просто организованное по-разному, я бы сказал, что между ними нет существенной разницы. «Вложенная петля», в которой нижний рычаг создает один ряд, в значительной степени совпадает с подвыбором из одного ряда.

Объединения носят более общий характер, поскольку использование скалярных подвыборов не распространяется, например, на получение двух столбцов из любой из этих вспомогательных таблиц.

0 голосов
/ 14 января 2011

Индексируется ли этот столбец таблицы? r.article_seq

-> Seq Scan на kbreview r (стоимость = 0.00..14.54 строк = 1 ширина = 12) (фактическое время = 0.267..1.175 строк = 1 петли = 1)

Здесь больше всего времени тратится.

...