Any fool can write code that a computer can understand. Good programmers write code that humans can understand. — Martin Fowler
Вступление
За последние пять лет мне довелось поработать в трёх разных компаниях, но ни в одной из них я не встречал SQL запросы, которые выглядели бы опрятно и легко читались (не считая редких исключений). Как правило попадаются запросы написанные как попало: в них случайным образом скачут отступы и меняется регистр, они плохо структурированы и непоследовательны, зачастую ещё и написаны не очень эффективно. Открывая такой запрос приходится потратить немалое время, чтобы начать хоть что-то в нём понимать. А через месяц, встретив этот же запрос снова, придётся опять в нём разбираться. Многие люди вообще относятся к сиквелу как к второсорному языку, не проявляя к нему никакого уважения. Но уважения они не проявляют не только к языку, но и к другим разработчикам, которым в будущем приходится читать и поддерживать такие запросы.
Ниже я привожу 8 простых правил основанных на личном опыте. Следуя им, ваши запросы будут легко читаемыми и простыми для понимания другими разработчиками.
1. Никакого капса
В давние времена, когда редакторы кода не имели возможности подсвечивать синтаксис, было принято писать ключевые слова заглавными буквами. С тех пор эта привычка крепко укоренилась в головах некоторых разработчиков и они продолжают следовать этой традиции. Некоторые пошли ещё дальше, и стали писать капсом вообще всё: имена таблиц, стобцов и пр. На деле же, любой современный редактор кода имеет подстветку ситнаксиса (в т. ч. и для встроенных языков, если вы пишете запрос внутри другого языка). SELECT
, FROM
, WHERE
навряд ли помогут вам понять суть запроса, а вот внимание на себя отвлекать однозначно будут.
За 5 лет что я пишу SQL запросы, я редко встречал те которые можно назвать «образцовыми»: где все ключевые слова выделены капсом, а не ключевые нет. Зато смешивание этих стилей попадается сплошь и рядом.
2. Перенос строк
Тут я выделяю понятия остновных ключевых слов и второстепенных (вложенных). Так, например, select
, from
и where
являются основными, join
, on
, and
второстепенными. Основные слова выравнены по левому краю, второстепенные в зависимости от уровня вложенности сдвигаются вправо:
select ...
from table1
join table2
on
and
where ...
and ...
3. Отступы
В SQL предпочтительней использовать отступы из 2 пробелов. Запросы с такими отсупами выглядят опрятней и компактней в сравнении с другими вариантами.
4. Перечисления
В тех случая когда столбцов в запросе несколько, предпочтительней писать каждый из них с новой строки:
select
id,
name,
type_id
...
5. Соединения
Тема соединений таблиц всегда была очень болезненной. Когда-то и я перечислял имена таблиц через запятую, а все соединения наряду с предикатами делал в блоке where
используя (+)
вместо left join
. Но, такая запись трудна для восприятия человеком, читающим этот запрос. Основных аргументов в её пользу, которые мне доводилось слышать, два: 1) ANSI соединения в оракле работают медленнее (на данный момент это уже не актуально); 2) глазам не приходится бегать по всему запросу, т. к. все условия находятся в одном месте. Аргумент 2 не выдерживает никакой критики, скорее это закостенелая привычка от которой сложно изавиться людям давно использующим такой синтаксис. Когда все условия собраны в where
, это больше похоже на месиво в котором чёрт ногу сломит. Напротив, при использовании ANSI соединений, запрос выглядит опрятным, каждое такое соединение и его уточнение сосредоточено сразу под именем таблицы, а в блоке where
находится лишь окончательный предикат глядя на который становится видно саму суть.
...
from objects file
join parameters path
on path.object_id = file.id
and path.attr_id = 123
where file.type_id = 404;
Обратите внимание, что в условии соединения столбец текущей таблицы стоит слева, а столбец внешней таблицы стоит справа от знака равенства.
Нередко авторы запросов заключают в скобки условия соединений:
...
from objects file
join parameters path
on (path.object_id = file.id
and path.attr_id = 123)
where file.type_id = 404;
Сути это не меняет, а определённый шум вносит, поэтому лучше обойтись без них.
6. Алиасы для таблиц
Они должны обозначать, то что выбирается из таблицы. Алиасы лучше чем комментарии рядом с идентификаторами, т. к. они позволяют в любом месте запроса сразу понять о чём идёт речь, в случае с комментарием вам придётся искать его и держать в уме связь между id и именем.
Плохо:
select
obj.name,
p.value as message
from objects obj
join params p
on p.object_id = obj.id
and p.attr_id = 995 -- content
where obj.type_id = 110; -- mail
Хорошо:
select
mail.name,
content.value as message
from objects mail
join params content
on content.object_id = mail.id
and content.attr_id = 995
where mail.type_id = 110;
Во втором случае также можно добавить комментарии рядом с идентификатороми, но как по мне, это излишне.
7. Запятые
Кто-то переносит запятую в перечислении на новую строку:
select
field1
, field2
, field3
Я не сторонник такого подхода. Конечно, это вносит определённое удобство при добавлении новых стобцов в запрос, но выглядит уродско.
8. Скобки
Парные скобки должны быть либо на одной строке, либо закрывающая скобка выровнена по началу блока к котором она принадлежит:
select name
from table1
where field1 in (..., ..., ...,)
and field2 in (
...,
...,
...
)
Также обратите внимание, что если в where
сразу же идёт какое-то перечисление, то такой предикат следует перенести на новую строчку, чтобы правило скобок не было нарушено:
select
...
from table1
where
field1 in (
...
)
and ...;
Ещё вариант:
select
...,
(
select foo
from table
where ...
) as bar,
...
Ещё несколько примеров
select
id,
name,
parent_id
from objects descriptor
where type_id = 666
order by name;
select
id,
name,
type_id
from objects descriptor
where
type_id in (
...
)
and name like 'zek%';
with
table1 as (
...
),
table2 as (
...
)
select
...
from table1
join table2
on table2.fieldA = table1.fieldA
where table1.fieldB = 'blah';
Вывод
Несомненно, этот список не явлется исчерпывающим, и вы сами с легкостью можете его расширить. Вероятно с какими-то пунктами вы даже не согласитесь. Цель этой заметки заключается в том, чтобы обратить внимание на тот код который мы пишем, не важно на каком языке, важно как мы это делаем. Спасибо.