MySQL — сложные запросы
Привет. Стал я тут писать одно Web-приложение и столкнулся с тем что на вывод одной таблице у меня получается около 4 запрос в БД. Если делать мини сервис с мелкой посещаемостью, то нагрузка как бы не о чем. А вот если людей будет уже около 2000 тысяч хотя бы в сутки, то запросы растут с геометрической прогрессией.
Чтобы не нагружать мой сервер, решил я более глубоко погрузится в MySQL и выяснил, что можно составлять сложные запросы к Базе Данных(БД). Т.е. было 4 select к БД, а стал один с вложенными запросами и join`ами.
К тому же сложные запросы MySQL помогут сократить код логики. Раньше было 4 запроса и соответственно получали 4 массива, каждый нужно было обойти, придать ему нужный вид, дальше объединить его с другими. А сейчас получается один запрос и один массив, все.
Задача
Возьмем абстрактную задачу: Вывести курс ЦБ на страницу.
Выводим следующее:
- Даллар США (это название валюты на русском).
- USD (это название валюты на английском).
- Текущая дата.
- Значение валюты.
- Вчерашняя дата.
- Значение валюты.
- Колонка разность (отянть вчера от сегодня).
И так представим, что БД у нас построена по правилам «Трех нормальных форм». Т.е. 1 и 2 пункт из списка выше хранится в одной таблице, 3-6 хранятся данные в другой таблице. А 7 пункт вообще вычисляется средствами MySql.
Сам код запроса
Запрос будет выглядеть следующем образом.
SELECT r.id_name_currency, r.value, yesterday.value, r.date, yesterday.date, pc.name_currency_en, pc.name_currency_ru, (yesterday.value - r.value) FROM parser_all_exchange_rates r JOIN ( SELECT rr.date, rr.value, rr.id_name_currency FROM parser_all_exchange_rates rr WHERE rr.id_name_banks = 233 AND rr.date = CURRENT_DATE() - INTERVAL 1 DAY ) yesterday JOIN parser_name_currencies pc ON r.id_name_currency = pc.id WHERE r.id_name_banks = 233 AND r.date = CURRENT_DATE() AND yesterday.id_name_currency = r.id_name_currency
В начале для легкости понимания лучше разбить задачу на блоки.
Пишем отдельные селекты для получения тех данных, которые нужны из разных таблиц, и только после этого начинаем их объединять. В дальнейшем с приобретением опыта, вы сами поймете когда это случится, будите уже писать сразу сложный запрос без разбивания его на блоки.
Нюансы
А как же без них.
FROM parser_all_exchange_rates r, ( SELECT rr.date, rr.value, rr.id_name_currency FROM parser_all_exchange_rates rr WHERE rr.id_name_banks = 233 AND rr.date = CURRENT_DATE() - INTERVAL 1 DAY ) yesterday INNER JOIN parser_name_currencies pc ON r.id_name_currency = pc.id
Если посмотреть на код выше, то после from идет указатель на имя таблицы, в которой мы ищем информацию, затем идет в скобках следующая таблица, после скобок ей присваивается имя yesterday и затем указываем join. Если написать так, то будет синтаксическая ошибка.
Join можно перенести на верх и вставить его перед скобками и поставить запятую, то все отработает, но это все равно не верно. Нужно писать более универсально. Т.е. т.к. в первом примере.
Необязательно писать INNER JOIN, можно просто JOIN. СУБД по умолчанию выполнить именно внутреннее соединение.
Будут вопросы пишите в комментариях.
Предыдущая