Постгрес новичок здесь.
Мне интересно, оптимизирован ли этот запрос или нет? Я попытался присоединиться только к тем значениям, которые на 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? Почему или почему это не имеет смысла?
SELECT version();
)Ответы:
По логике вещей , совершенно не имеет значения, помещаете ли вы условия в условие соединения
INNER JOIN
или вWHERE
то же самое условиеSELECT
. Эффект тот же.(Не подходит для
OUTER JOIN
!)При работе с настройками по умолчанию это также не имеет значения для плана запроса или производительности . Postgres волен изменения порядка соединения и
JOIN
&WHERE
условие в своем стремлении к лучшему плану запроса - до тех пор , как количество таблиц не больше , чемjoin_collapse_limit
( по умолчанию8
). Подробности:Для удобочитаемости и удобства обслуживания имеет смысл размещать условия, связывающие таблицы в соответствующем
JOIN
пункте, и общие условия в этомWHERE
разделе.Ваш запрос выглядит просто отлично. Я бы использовал псевдонимы таблиц, чтобы уменьшить шум.
Незначительная деталь:
int2 '1'
или даже1::int2
более разумны, чем(1)::INT2
. И хотя по сравнению со значением четко определенного числового типа данных, достаточно простой числовой константы1
.источник
Пара моментов ..
Если в вашем случае вы объединяете условие с тем же именем (
user_id
), вы можете использоватьUSING (user_id)
вместоON (a.user_id = b.user_id)
. Это также спасает избыточный столбец от возможного вывода (если вы работаетеSELECT *
в производстве).1::int2
проблематично. Либоstatus
, иis_primary
другие ужеint2
в этом случае, литерал 1 будет автоматически приведен к int2, или int2 приведен к int, как pg сочтет нужным. Или, если вы храните их как обычные целочисленные типы и приводите их в порядок, как если бы это имело значение в вычислениях - а это не так, только приведение делает это проигрышным предложением.Когда это возможно, все :: int2, вероятно, должны храниться как
boolean
. Тогда вы можете написать своеWHERE
условие, чтобы быть проще.Для вашего типа и статуса, вы можете захотеть
ENUM
тип.источник