powered by simpleCommunicator - 2.0.61     © 2026 Programmizd 02
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Форумы / PostgreSQL [игнор отключен] [закрыт для гостей] / К какому стилю запросов лучше стремиться:
8 сообщений из 8, страница 1 из 1
К какому стилю запросов лучше стремиться:
    #38592414
R1K0
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Есть один запрос, написанный 2 способами и EXPLAIN ANALYZE на него. Результат времени выполнения практически одинаков. Хотелось бы узнать - как же все-таки делать это правильнее:

Вариант 1.

Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
9.
EXPLAIN ANALYZE SELECT name, layer, linktype_id
  FROM taskdesc
 WHERE task_id IN (
       SELECT task_id
         FROM questtasklink
        WHERE quest_id = (
              SELECT quest_id
                FROM questdesc
               WHERE name = 'Begin Training'));



Вывод:

Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
QUERY PLAN
Nested Loop  (cost=2.14..10.43 rows=1 width=154) (actual time=0.143..0.277 rows=5 loops=1)
  InitPlan 1 (returns $0)
    ->  Seq Scan on questdesc  (cost=0.00..1.08 rows=1 width=4) (actual time=0.017..0.026 rows=1 loops=1)
          Filter: ((name)::text = 'Begin Training'::text)
  ->  HashAggregate  (cost=1.06..1.08 rows=1 width=4) (actual time=0.106..0.117 rows=5 loops=1)
        ->  Seq Scan on questtasklink  (cost=0.00..1.06 rows=1 width=4) (actual time=0.056..0.072 rows=5 loops=1)
              Filter: (quest_id = $0)
"  ->  Index Scan using ""PK__TASK_DESC"" on taskdesc  (cost=0.00..8.27 rows=1 width=158) (actual time=0.017..0.021 rows=1 loops=5)"
        Index Cond: (task_id = questtasklink.task_id)
Total runtime: 0.567 ms



Вариант 2.

Код: plsql
1.
2.
3.
4.
5.
EXPLAIN ANALYZE SELECT td.name, td.layer, td.linktype_id
  FROM taskdesc AS td, questdesc AS qd, questtasklink AS qtl
 WHERE qtl.quest_id = qd.quest_id
   AND qtl.task_id = td.task_id
   AND qd.name = 'Begin Training'



Вывод:

Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
QUERY PLAN
Nested Loop  (cost=0.00..7.27 rows=1 width=154) (actual time=0.099..0.260 rows=5 loops=1)
  ->  Nested Loop  (cost=0.00..2.19 rows=1 width=4) (actual time=0.062..0.099 rows=5 loops=1)
        Join Filter: (qd.quest_id = qtl.quest_id)
        ->  Seq Scan on questdesc qd  (cost=0.00..1.08 rows=1 width=4) (actual time=0.030..0.039 rows=1 loops=1)
              Filter: ((name)::text = 'Begin Training'::text)
        ->  Seq Scan on questtasklink qtl  (cost=0.00..1.05 rows=5 width=8) (actual time=0.009..0.019 rows=5 loops=1)
"  ->  Index Scan using ""PK__TASK_DESC"" on taskdesc td  (cost=0.00..5.07 rows=1 width=158) (actual time=0.018..0.022 rows=1 loops=5)"
        Index Cond: (task_id = qtl.task_id)
Total runtime: 0.512 ms



Действительно, очень интересно узнать. Заранее спасибо.
...
Рейтинг: 0 / 0
К какому стилю запросов лучше стремиться:
    #38592436
Фотография Степан H.
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
R1K0,

старайтесь IN избегать, лучше EXISTS
...
Рейтинг: 0 / 0
К какому стилю запросов лучше стремиться:
    #38592748
LeXa NalBat
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
вот еще парочка вариантов для размышлений :)

Код: sql
1.
2.
3.
4.
5.
SELECT td.name, td.layer, td.linktype_id
FROM taskdesc AS td
JOIN questtasklink AS qtl ON qtl.task_id = td.task_id
JOIN questdesc AS qd ON qd.quest_id = qtl.quest_id
WHERE qd.name = 'Begin Training'


Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
WITH begin_training_questdesc AS (
 SELECT qd.quest_id
 FROM questdesc AS qd
 WHERE qd.name = 'Begin Training'
),
begin_training_questtasklink AS (
 SELECT qtl.task_id
 FROM questtasklink AS qtl
 JOIN begin_training_questdesc AS qd ON qtl.quest_id = qd.quest_id
)
SELECT td.name, td.layer, td.linktype_id
FROM taskdesc AS td
JOIN begin_training_questtasklink AS qtl ON qtl.task_id = td.task_id
...
Рейтинг: 0 / 0
К какому стилю запросов лучше стремиться:
    #38593209
R1K0
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Да, про JOIN я читал, но как-то олдскул уже в крови (да и, скорее всего, это не более чем syntax sugar, или я не прав?), а пример с WITH уж больно громоздкий имхо, Хотя, конечно, блочность упрощает отладку в особо крутых запросах.

Мои вопрос скорее в том, что же в общем случае лучше - подзапросы или связь таблиц?
...
Рейтинг: 0 / 0
К какому стилю запросов лучше стремиться:
    #38593252
LeXa NalBat
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
R1K0Да, про JOIN я читал, но как-то олдскул уже в крови (да и, скорее всего, это не более чем syntax sugar, или я не прав?)до тех пор, пока не понадобится outer джоин

R1K0Мои вопрос скорее в том, что же в общем случае лучше - подзапросы или связь таблиц?мне кажется, каждая запись уместна для своего случая. в данном примере, когда ограничения накладываются только на одну таблицу questdesc, а затем нужно выбрать соттветствующие записи из второй таблицы, затем соответствующие им из третьей и вернуть их... в этом случае самой понятной мне кажется запись через with. и надо не забывать про постгресовую специфику выполнения with запроса - предвычисление.
...
Рейтинг: 0 / 0
К какому стилю запросов лучше стремиться:
    #38593456
biwed.ru
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
R1K0,
Добрый день.
Запрос 1
Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
SELECT name, layer, linktype_id
  FROM taskdesc
 WHERE task_id IN (
       SELECT task_id
         FROM questtasklink
        WHERE quest_id = (
              SELECT quest_id
                FROM questdesc
               WHERE name = 'Begin Training'));


При смене СУБД работать будут не эффективно, особенно при увеличении результатов в подзапросе. Стараюсь уходить от таких запросов.

Запрос 2
Код: sql
1.
2.
3.
4.
5.
SELECT td.name, td.layer, td.linktype_id
  FROM taskdesc AS td, questdesc AS qd, questtasklink AS qtl
 WHERE qtl.quest_id = qd.quest_id
   AND qtl.task_id = td.task_id
   AND qd.name = 'Begin Training'


Я рекомендую его. Однако он эквивалентен объединению таблиц только через INNER JOIN.

Запрос 3
Код: sql
1.
2.
3.
4.
5.
SELECT td.name, td.layer, td.linktype_id
FROM taskdesc AS td
JOIN questtasklink AS qtl ON qtl.task_id = td.task_id
JOIN questdesc AS qd ON qd.quest_id = qtl.quest_id
WHERE qd.name = 'Begin Training'


Не совсем приятный запрос при использовании LEFT, RIGHT и FULL объединений. Не приятность в WHERE qd.name = 'Begin Training' . В данном случае нужно помнить, что WHERE .... действует на все таблицы.

Из опыта могу посоветовать стараться не использовать LEFT и RIGHT, так как построить правильный запрос не всегда можно быстро. А если есть такая необходимость (использовать LEFT и RIGHT), старайтесь проверять мощности полученных множеств через count().

PS. Буду рад, если инфа окажется полезной.
...
Рейтинг: 0 / 0
К какому стилю запросов лучше стремиться:
    #38594559
PCContra
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
R1K0Да, про JOIN я читал, но как-то олдскул уже в крови (да и, скорее всего, это не более чем syntax sugar, или я не прав?), а пример с WITH уж больно громоздкий имхо, Хотя, конечно, блочность упрощает отладку в особо крутых запросах.

Мои вопрос скорее в том, что же в общем случае лучше - подзапросы или связь таблиц?
R1K0 , синтаксическим подсластителем JOIN не являются. Запросы с ними выполняются намного быстрее. В вашем случае
Код: sql
1.
2.
3.
4.
5.
SELECT td.name, td.layer, td.linktype_id
  FROM taskdesc AS td, questdesc AS qd, questtasklink AS qtl
 WHERE qtl.quest_id = qd.quest_id
   AND qtl.task_id = td.task_id
   AND qd.name = 'Begin Training'


происходит сравнение каждой строки таблицы с каждой строкой другой таблицы. Зависимость для двух таблиц будет квадратичная, для трех - в кубе (при равном числе записей, ну а для разного количества - равно их произведению). Механизм Join'ов отличается, по факту он работает куда быстрее. Сужу по своему опыту
...
Рейтинг: 0 / 0
К какому стилю запросов лучше стремиться:
    #38594633
qwwq
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
PCContraR1K0Да, про JOIN я читал, но как-то олдскул уже в крови (да и, скорее всего, это не более чем syntax sugar, или я не прав?), а пример с WITH уж больно громоздкий имхо, Хотя, конечно, блочность упрощает отладку в особо крутых запросах.

Мои вопрос скорее в том, что же в общем случае лучше - подзапросы или связь таблиц?
R1K0 , синтаксическим подсластителем JOIN не являются. Запросы с ними выполняются намного быстрее. В вашем случае
Код: sql
1.
2.
3.
4.
5.
SELECT td.name, td.layer, td.linktype_id
  FROM taskdesc AS td, questdesc AS qd, questtasklink AS qtl
 WHERE qtl.quest_id = qd.quest_id
   AND qtl.task_id = td.task_id
   AND qd.name = 'Begin Training'


происходит сравнение каждой строки таблицы с каждой строкой другой таблицы. Зависимость для двух таблиц будет квадратичная, для трех - в кубе (при равном числе записей, ну а для разного количества - равно их произведению). Механизм Join'ов отличается, по факту он работает куда быстрее. Сужу по своему опыту

cross join (т.е. декарт) с фильтром where как правило распознаётся и планируется оптимизатором постгреса в точности так же , как INNER JOIN с соответствующим (фильтру кросса) условием связи в ON (using). само предложение (CROSS|INNER|OUTER) за скорость связывания не отвечает, никакой магии в слове INNER (или JOIN) нет

за некое ускорение в разных случаях могут отвечать правильно созданные индексы + правильно (в соответствии с построенными индексами) наложенные условия. (можно написать условие [и в ON и в WHERE] так, что оптимизатор не сможет воспользоваться годным под него индексом)


кроме всего прочего, join отличается от изначальной задачи (exists|in) в случае проверок по не ключевым полям. (по ключевым -- и планы [exists | inner], как правило, совпадают, иногда на удивление). И тогда потребует дополнения DISTINCT-ом, что всегда плохо.
...
Рейтинг: 0 / 0
8 сообщений из 8, страница 1 из 1
Форумы / PostgreSQL [игнор отключен] [закрыт для гостей] / К какому стилю запросов лучше стремиться:
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]