Язык SQL работает со множествами. Это важно понимать при работе с несколькими таблицами и вложенными запросами. Обычно эти множества можно нарисовать как круги, чтобы понять что нам нужно получить (заштриховать требуемые области пересечений). Таблицы же можно фильтровать и сортировать.
SQL в деталях довольно сильно разный в разных базах. Такие вещи как достать год из даты обычно весьма специфичны для каждой базы и даже типа колонки.
Для быстрых запросов нужны индексы. Они ускоряют извлечение данных, но замедляют запись и увеличивают размер базы, поэтому нужен баланс.
Псевдокод таблиц для примера запросов:
users: id, name, age
teams: id, name, create_at
users_in_groups: user_id, group_id
Вывести все группы пользователей с больше, чем 5-ью совершеннолетними пользователями, по уменьшению кол-ва совершеннолетних пользователей:
SELECT
t.name as team_name,
COUNT(u.id) as amount
FROM
teams t,
users u,
users_in_teams u2t
WHERE
u2t.user_id = u.id
AND u2t.team_id = t.id
AND u.age > 18
GROUP BY t.name
HAVING COUNT(u.id) > 5
ORDER BY COUNT(u.id) DESC
Вывести группы по алфавитному порядку с кол-вом пользователей (выводить даже 0):
SELECT
t.name as team_name,
COUNT(u.id) as amount
FROM
teams t
LEFT JOIN users_in_teams u2t ON u2t.team_id = t.id
LEFT JOIN users u ON u2t.user_id = u.id
GROUP BY t.name
ORDER BY t.name ASC
Вывести группы по алфавитному порядку с кол-вом совершеннолетних пользователей (выводить даже 0):
SELECT
t.name as team_name,
IFNULL(team_with_amount.amount, 0) as amount
FROM teams t
LEFT JOIN (SELECT
t2.id as team_id,
t2.name as team_name,
COUNT(u.id) as amount
FROM
teams t2,
users u,
users_in_teams u2t
WHERE
u2t.user_id = u.id
AND u2t.team_id = t2.id
AND u.age > 18
GROUP BY t2.id, t2.name) as team_with_amount
ON t.id = team_with_amount.team_id
ORDER BY t.name ASC
Если можете прочитать и написать такие SQL-запросы, то обычно такого уровня понимания достаточно. Если сейчас непонятно, то лучше подучить это немного – на собеседованиях практически всегда что-то подобное спрашивают. Да и на практике оно нужно.
ACID свойства транзакций:
- Atomicity (атомарность) - применилась или откатилась
- Consistency (согласованность) - транзакция не нарушает согласованности данных
- Isolation (изолированность) - как если бы транзакции шли последовательно
- Durability (долговечность) - если применилась, то невозможно потерять данные
Ну и уровни изоляций:
- Read uncommitted (чтение незафиксированных данных) – все плохо, но без блокировок
- Read committed (чтение фиксированных данных) – по умолчанию – изменения строк могут появляться внутри транзакции, если другая транзакция закончилась
- Repeatable read (повторяющееся чтение) – но новые строки могут появляться внутри транзакции от других транзакций
- Serializable (упорядочиваемость) – все хорошо, но медленно