План запроса: важен ли порядок СОЕДИНЕНИЙ - PullRequest
1 голос
/ 22 мая 2019

Я хочу проверить, важен ли порядок JOINS в SQL-запросе для времени выполнения и эффективности.

Я использую PostgreSQL и для своей проверки я использовал пример world db из MYSQL (https://downloads.mysql.com/docs/world.sql.zip)) и написал эти два утверждения:

Запрос 1:

EXPLAIN ANALYSE SELECT * FROM countrylanguage
    JOIN city ON city.countrycode = countrylanguage.countrycode
    JOIN country c ON city.countrycode = c.code

Запрос 2:

EXPLAIN ANALYSE SELECT * FROM city
    JOIN country c ON c.code = city.countrycode
    JOIN countrylanguage c2 on c.code = c2.countrycode

План запроса 1: enter image description here

Hash Join  (cost=41.14..484.78 rows=29946 width=161) (actual time=1.472..17.602 rows=30670 loops=1)
  Hash Cond: (city.countrycode = countrylanguage.countrycode)
  ->  Seq Scan on city  (cost=0.00..72.79 rows=4079 width=31) (actual time=0.062..1.220 rows=4079 loops=1)
  ->  Hash  (cost=28.84..28.84 rows=984 width=130) (actual time=1.378..1.378 rows=984 loops=1)
        Buckets: 1024  Batches: 1  Memory Usage: 172kB
        ->  Hash Join  (cost=10.38..28.84 rows=984 width=130) (actual time=0.267..0.823 rows=984 loops=1)
              Hash Cond: (countrylanguage.countrycode = c.code)
              ->  Seq Scan on countrylanguage  (cost=0.00..15.84 rows=984 width=17) (actual time=0.029..0.158 rows=984 loops=1)
              ->  Hash  (cost=7.39..7.39 rows=239 width=113) (actual time=0.220..0.220 rows=239 loops=1)
                    Buckets: 1024  Batches: 1  Memory Usage: 44kB
                    ->  Seq Scan on country c  (cost=0.00..7.39 rows=239 width=113) (actual time=0.013..0.137 rows=239 loops=1)
Planning Time: 3.818 ms
Execution Time: 18.801 ms

План запроса 2: enter image description here

Hash Join  (cost=41.14..312.47 rows=16794 width=161) (actual time=2.415..18.628 rows=30670 loops=1)
  Hash Cond: (city.countrycode = c.code)
  ->  Seq Scan on city  (cost=0.00..72.79 rows=4079 width=31) (actual time=0.032..0.574 rows=4079 loops=1)
  ->  Hash  (cost=28.84..28.84 rows=984 width=130) (actual time=2.364..2.364 rows=984 loops=1)
        Buckets: 1024  Batches: 1  Memory Usage: 171kB
        ->  Hash Join  (cost=10.38..28.84 rows=984 width=130) (actual time=0.207..1.307 rows=984 loops=1)
              Hash Cond: (c2.countrycode = c.code)
              ->  Seq Scan on countrylanguage c2  (cost=0.00..15.84 rows=984 width=17) (actual time=0.027..0.204 rows=984 loops=1)
              ->  Hash  (cost=7.39..7.39 rows=239 width=113) (actual time=0.163..0.163 rows=239 loops=1)
                    Buckets: 1024  Batches: 1  Memory Usage: 44kB
                    ->  Seq Scan on country c  (cost=0.00..7.39 rows=239 width=113) (actual time=0.015..0.049 rows=239 loops=1)
Planning Time: 1.901 ms
Execution Time: 19.694 ms

Оценочные затраты и строки различны, а последнее условие хеширования отличается. Означает ли это, что Планировщик запросов не выполнил одно и то же для обоих запросов, или я ошибаюсь?

Спасибо за вашу помощь!

Ответы [ 2 ]

2 голосов
/ 22 мая 2019
  • (как сказано) запросы не идентичны
  • хотя и не идентичны, планы сопоставимы
  • оба запроса выполняются за 18 мс, сравнение их практически бесполезно
  • запросы к таблицам с недостаточной структурой (ключи, индексы, статистика), но с достаточно малым размером (work_mem) всегда будут приводить к хеш-соединениям.
2 голосов
/ 22 мая 2019

Проблема не в порядке join с, а в том, что условия join отличаются - ссылаясь на разные таблицы.

В первом запросе вы присоединяетесь к countrylanguage, используя код страны от city. Во втором вы используете код страны от country.

С внутренними объединениями это не должно иметь значения для конечного результата. Однако это явно влияет на то, как оптимизатор рассматривает разные пути.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...