Условия Postgres JOIN против условий WHERE

12

Постгрес новичок здесь.

Мне интересно, оптимизирован ли этот запрос или нет? Я попытался присоединиться только к тем значениям, которые на 100% необходимы, и оставил все динамические условия в предложении WHERE. См. ниже.

SELECT *
    FROM
      myapp_employees
    JOIN myapp_users ON
      myapp_users.user_id=myapp_employees.user_id
    JOIN myapp_contacts_assoc ON
      myapp_contacts_assoc.user_id=myapp_users.user_id
    JOIN myapp_contacts ON
      myapp_contacts.contact_id=myapp_contacts_assoc.contact_id
    WHERE
      myapp_contacts.value='test@gmail.com' AND
      myapp_contacts.type=(1)::INT2 AND
      myapp_contacts.is_primary=(1)::INT2 AND
      myapp_contacts.expired_at IS NULL AND
      myapp_employees.status=(1)::INT2 AND
      myapp_users.status=(1)::INT2
    LIMIT 1;

Примечание: для контекста этот процесс проверяет, является ли пользователь также сотрудником (повышенный уровень привилегий / другой тип пользователя).

В любом случае, это правильный путь? Должно ли JOIN ON содержать больше операторов, например, для проверки expired_at IS NULL? Почему или почему это не имеет смысла?

Дэн
источник
А как насчет вашей версии Postgres? ( SELECT version();)
Эрвин Брандштеттер
@ErwinBrandstetter Я использую PostgreSQL 9.3.14. Должно ли это быть то, что мне нужно в каждой функции?
Дан
2
Нет, мы здесь, на dba.SE, требуем от вас объявить соответствующие версии программного обеспечения, потому что они имеют значение для многих вопросов.
Эрвин Брандштеттер

Ответы:

14

По логике вещей , совершенно не имеет значения, помещаете ли вы условия в условие соединения INNER JOINили в WHEREто же самое условие SELECT. Эффект тот же.

(Не подходит для OUTER JOIN!)

При работе с настройками по умолчанию это также не имеет значения для плана запроса или производительности . Postgres волен изменения порядка соединения и JOIN& WHEREусловие в своем стремлении к лучшему плану запроса - до тех пор , как количество таблиц не больше , чем join_collapse_limit( по умолчанию 8). Подробности:

Для удобочитаемости и удобства обслуживания имеет смысл размещать условия, связывающие таблицы в соответствующем JOINпункте, и общие условия в этом WHEREразделе.

Ваш запрос выглядит просто отлично. Я бы использовал псевдонимы таблиц, чтобы уменьшить шум.

Незначительная деталь:

int2 '1'или даже 1::int2более разумны, чем (1)::INT2. И хотя по сравнению со значением четко определенного числового типа данных, достаточно простой числовой константы 1.

Эрвин Брандштеттер
источник
2

Пара моментов ..

  1. Если в вашем случае вы объединяете условие с тем же именем ( user_id), вы можете использовать USING (user_id)вместо ON (a.user_id = b.user_id). Это также спасает избыточный столбец от возможного вывода (если вы работаете SELECT *в производстве).

  2. 1::int2проблематично. Либо status, и is_primaryдругие уже int2в этом случае, литерал 1 будет автоматически приведен к int2, или int2 приведен к int, как pg сочтет нужным. Или, если вы храните их как обычные целочисленные типы и приводите их в порядок, как если бы это имело значение в вычислениях - а это не так, только приведение делает это проигрышным предложением.

  3. Когда это возможно, все :: int2, вероятно, должны храниться как boolean. Тогда вы можете написать свое WHEREусловие, чтобы быть проще.

  4. Для вашего типа и статуса, вы можете захотеть ENUMтип.

Эван Кэрролл
источник