MySQL — система управления базами данных
MySQL — одна из самых популярных реляционных систем управления базами данных в мире. Она используется на миллионах сайтов и приложений для хранения и обработки данных.
1. Что такое MySQL
MySQL — свободная реляционная СУБД с открытым исходным кодом, разрабатываемая компанией Oracle. Она используется повсеместно:
- Веб-приложения — WordPress, Joomla, Drupal работают на MySQL.
- Электронная коммерция — Magento, PrestaShop.
- Социальные сети и стартапы — быстрый старт, богатая экосистема.
Клиент-серверная архитектура
MySQL работает по модели «клиент — сервер». Сервер mysqld слушает порт 3306 и обрабатывает запросы от клиентов — консольной утилиты mysql, GUI-инструментов или приложений на Python.
2. Установка MySQL
Скачай MySQL Installer с официального сайта dev.mysql.com.
| ОС | Рекомендация |
|---|---|
| Windows | MySQL Installer (MSI) — включает Workbench |
| macOS | DMG-пакет или brew install mysql |
| Linux (Debian/Ubuntu) | sudo apt install mysql-server |
3. Подключение и первые команды
Подключись к серверу через консоль:
mysql -u root -pСистема запросит пароль, после чего ты окажешься в интерактивной оболочке MySQL. Вот базовые команды:
SHOW DATABASES;
SELECT VERSION();
SELECT NOW();
STATUS;
QUIT;Каждая команда завершается точкой с запятой ;. Без неё клиент будет ждать продолжения.
4. Создание базы данных и таблиц
Создай базу данных с правильной кодировкой:
CREATE DATABASE shop
CHARACTER SET utf8mb4
COLLATE utf8mb4_unicode_ci;Переключись на неё и создай таблицу:
USE shop;
CREATE TABLE products (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(100) NOT NULL,
price DECIMAL(10, 2) NOT NULL,
category ENUM('books', 'electronics', 'clothing') NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
SHOW TABLES;
DESCRIBE products;5. Типы данных MySQL
| Тип | Размер | Описание |
|---|---|---|
| INT | 4 байта | Целые числа от −2 млрд до +2 млрд |
| BIGINT | 8 байт | Очень большие целые числа |
| VARCHAR(n) | до n символов | Переменная строка фиксированной максимальной длины |
| TEXT | до 64 КБ | Длинный текст, статьи, описания |
| DECIMAL(p, s) | точный | Дробные числа без потери точности (деньги) |
| DATE | 3 байта | Дата: ГГГГ-ММ-ДД |
| TIMESTAMP | 4 байта | Дата и время с автоматической меткой |
| ENUM | 1-2 байта | Значение из фиксированного списка |
6. Работа с данными
INSERT — добавление
INSERT INTO products (name, price, category)
VALUES ('Мышка Logitech', 1590.00, 'electronics'),
('Фантастика', 450.00, 'books'),
('Футболка Nike', 2990.00, 'clothing');SELECT — выборка
SELECT * FROM products;
SELECT name, price FROM products
WHERE category = 'electronics';
SELECT * FROM products
WHERE price < 1000
ORDER BY price ASC
LIMIT 10;
SELECT * FROM products
WHERE name LIKE '%мыш%';UPDATE и DELETE
UPDATE products
SET price = 1290.00
WHERE name = 'Мышка Logitech';
DELETE FROM products
WHERE id = 3;7. Порядок выполнения запроса и продвинутая выборка
Ключевые слова SQL выполняются строго в таком порядке: SELECT → FROM → WHERE → GROUP BY → HAVING → ORDER BY → LIMIT.
JOIN — соединение таблиц
Создадим таблицу заказов, связанную с товарами:
CREATE TABLE orders (
id INT AUTO_INCREMENT PRIMARY KEY,
product_id INT NOT NULL,
quantity INT NOT NULL DEFAULT 1,
order_date TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (product_id) REFERENCES products(id)
);
SELECT orders.id, products.name, orders.quantity, products.price
FROM orders
INNER JOIN products ON orders.product_id = products.id
ORDER BY orders.order_date DESC;GROUP BY и агрегатные функции
SELECT category, COUNT(*) AS cnt, AVG(price) AS avg_price
FROM products
GROUP BY category
HAVING avg_price > 500
ORDER BY cnt DESC;8. Пользователи и права
Работать под root в продакшене опасно — полные права могут привести к потере данных. Создавай отдельных пользователей:
CREATE USER 'app_user'@'localhost' IDENTIFIED BY 'Надёжный_Пароль123!';
GRANT SELECT, INSERT, UPDATE ON shop.* TO 'app_user'@'localhost';
FLUSH PRIVILEGES;
SHOW GRANTS FOR 'app_user'@'localhost';9. Резервное копирование и работа из Python
Экспорт и восстановление
mysqldump -u root -p shop > shop_backup.sql
mysql -u root -p shop < shop_backup.sqlПодключение из Python
Установи драйвер: pip install mysql-connector-python
Пример: SELECT из Python
import mysql.connector
conn = mysql.connector.connect(
host='localhost', user='app_user',
password='Надёжный_Пароль123!', database='shop'
)
cursor = conn.cursor()
cursor.execute('SELECT name, price FROM products WHERE category = %s', ('electronics',))
for row in cursor.fetchall():
print(f'{row[0]} — {row[1]} руб.')
cursor.close()
conn.close()Пример: INSERT из Python
import mysql.connector
conn = mysql.connector.connect(
host='localhost', user='app_user',
password='Надёжный_Пароль123!', database='shop'
)
cursor = conn.cursor()
sql = 'INSERT INTO products (name, price, category) VALUES (%s, %s, %s)'
data = ('Наушники Sony', 4990.00, 'electronics')
cursor.execute(sql, data)
conn.commit()
print(f'Добавлен товар с id: {cursor.lastrowid}')
cursor.close()
conn.close()10. Индексы и производительность запросов
Индекс — это структура данных (в MySQL — B-tree), которая ускоряет поиск по выбранным колонкам. Без индекса сервер сканирует таблицу построчно, с индексом находит строки за отсечки. Индексы стоит ставить на колонки из WHERE, JOIN и ORDER BY.
CREATE INDEX idx_products_category ON products(category);
EXPLAIN SELECT * FROM products
WHERE category = 'electronics' AND price > 1000;Число строк оценивайте через rows в EXPLAIN. Для чтения с пагинацией используйте OFFSET с индексом по ключу или движок InnoDB с первичным ключом.
11. Транзакции и уровни изоляции
Транзакция объединяет несколько операций в одну: либо все они применяются, либо ни одна. В MySQL транзакции поддерживает движок InnoDB (по умолчанию с 5.5).
START TRANSACTION;
UPDATE accounts SET balance = balance - 500
WHERE user_id = 42 AND balance >= 500;
UPDATE accounts SET balance = balance + 500
WHERE user_id = 17;
COMMIT; -- или ROLLBACK при ошибке- READ COMMITTED — видны только закоммиченные строки других транзакций.
- REPEATABLE READ — «снапшот» данных на начало транзакции (стандарт MySQL).
- SERIALIZABLE — полная блокировка чтения-записи, максимальная защита.
12. Хранимые процедуры и триггеры
Хранимая процедура — процедура на SQL, выполняемая на сервере. Она уменьшает сетевой трафик и централизует бизнес-логику. Триггер автоматически срабатывает до или после INSERT, UPDATE, DELETE.
DELIMITER $$
CREATE PROCEDURE update_price
(IN prod_id INT, IN delta DECIMAL(10,2))
BEGIN
UPDATE products
SET price = price + delta
WHERE id = prod_id;
END$$
DELIMITER ;
CALL update_price(101, 300.00);
CREATE TRIGGER products_updated_at
BEFORE UPDATE ON products
FOR EACH ROW SET NEW.updated_at = NOW();13. JSON, полнотекстовый поиск и ошибки новичков
| Возможность | Запрос |
|---|---|
| JSON в колонке | WHERE JSON_EXTRACT(doc, '$.name') = 'X' |
| Full-text индекс | MATCH(title) AGAINST('список') |
| Миграция колонки | ALTER TABLE ... CHANGE COLUMN |
Тип JSON валидирует данные на сервере и хранит их в бинарном виде — это удобнее и быстрее, чем строка с JSON. Для быстрого фильтра по JSON-полю создавайте generated-колонку с индексом.
- Не храните числа в VARCHAR — сравнение станет лексикографическим.
- Не используйте SELECT * в продакшене — читайте только нужные колонки.
- Проверяйте кодировку: utf8mb4 для эмодзи и сравнения без ошибок.
- Закрывайте соединения (close() или контекстный менеджер в Python).
Теперь ты знаешь основы MySQL: от установки до работы из Python. Рекомендуемый следующий шаг — изучение PostgreSQL для сравнения подходов, или углублённое изучение SQL для сложных запросов.
14. MySQL в Docker: воспроизводимая среда
Контейнер решает проблему «на моей машине работало»: версия сервера, кодировка и настройки фиксируются в одном файле. Образ mysql:8 готов к запуску за пару минут, а данные выносите в volume, чтобы они пережили пересоздание контейнера.
docker run --name mysql-dev -d \
-e MYSQL_ROOT_PASSWORD=root \
-e MYSQL_DATABASE=shop \
-p 3306:3306 \
-v mysql_data:/var/lib/mysql \
mysql:8После первого запуска не забудьте сменить пароль root и создать прикладного пользователя с минимальными правами. Для проекта удобнее docker-compose.yml: сервисы приложения и базы поднимаются одной командой, а настройки передаются через переменные окружения, а не захардкоженный конфиг.
15. Репликация и отказоустойчивость
Репликация создаёт копии данных на других серверах: реплика читает binlog ведущего и воспроизводит те же изменения. Основная польза — отказоустойчивость (при сбое ведущего роль берёт реплика) и разгрузка чтения через реплики, настроенные как только для чтения.
-- на ведущем
CREATE USER 'replica'@'%' IDENTIFIED BY 'replica_pass';
GRANT REPLICATION SLAVE ON *.* TO 'replica'@'%';
-- на реплике
CHANGE REPLICATION SOURCE TO
SOURCE_HOST='master',
SOURCE_USER='replica',
SOURCE_PASSWORD='replica_pass';
START REPLICA;Статус реплики контролируйте командой SHOW REPLICA STATUS\G: следите за Seconds_Behind_Source. Если оно растёт — реплика не успевает догонять нагрузку, и пора думать о шардировании или оптимизации запросов.
16. Binlog и восстановление на точку во времени
Бинарный журнал записывает все изменения данных. Он нужен не только для репликации, но и для восстановления после сбоя: дамп + последующие транзакции из binlog дают состояние ровно на нужный момент, а не на момент дампа.
# полный дамп
mysqldump --all-databases --single-transaction \
--master-data=2 > backup_sun.sql
# применение изменений до 14:30
mysqlbinlog --stop-datetime="2026-09-19 14:30:00" \
binlog.000023 | mysqlЗапланируйте бэкапы через cron или встроенный mysqldump-скрипт и храните копии на отдельной машине. Ключевое правило: бэкап без регулярной проверки восстановления — это просто лишний набор файлов.
| Тип | Скорость | Точность |
|---|---|---|
| mysqldump | медленный | логический, переносимый |
| физический (файлы) | быстрый | привязан к версии |
| binlog + дамп | средний | point-in-time |
17. Профилирование: slow log и performance_schema
Главные данные о проблeмных запросах лежат в журнале медленных запросов (slow query log). Включите его и задайте порог: всё, что выполняется дольше секунды, попадает в лог для разбора. Нагрузку при этом замеряет performance_schema.
SET GLOBAL slow_query_log = ON;
SET GLOBAL long_query_time = 1;
SET GLOBAL log_queries_not_using_indexes = ON;
SHOW VARIABLES LIKE 'slow%';Найдя медленный запрос, снимите план командой EXPLAIN ANALYZE — он показывает фактические затраты по каждой строке. Признаки проблем: полные сканирования (ALL), временная таблица и файловая сортировка. Решение чаще всего простое — создание индекса под условие WHERE.
- Следите за метрикой rows_examined: чем больше, тем слабее индекс.
- Не игнорivуйте медленные запросы в проде: они первыми «съедают» ресурсы при пике.
- Повторные замеры после оптимизации покажут реальный эффект изменений.
18. Партиционирование больших таблиц
Когда таблица разрастается до миллиардов строк, проще работать с частью данных, чем со всей. Партиционирование делит таблицу на физически отдельные сегменты по правилу, а оптимизатор отбрасывает неподходящие секции ещё до чтения — это partition pruning.
CREATE TABLE orders (
id INT NOT NULL,
created_at DATE NOT NULL,
amount DECIMAL(10,2),
PRIMARY KEY (id, created_at)
) PARTITION BY RANGE (YEAR(created_at))
(PARTITION p2024 VALUES LESS THAN (2025),
PARTITION p2025 VALUES LESS THAN (2026),
PARTITION p2026 VALUES LESS THAN (2027));Архивные секции удаляются мгновенно — отбрасывается целая партиция, а не миллионы строк. Однако ключ партиционирования обязан входить в первичный ключ, а каждый индекс тоже «режется» на части.
19. InnoDB изнутри: буферный пул и MVCC
Двигатель InnoDB держит самые нужные данные и индексы в памяти — в буферном пуле. Чем больше пул, тем реже MySQL обращается к диску. Классическая настройка для выделенного сервера — 70–80% оперативной памяти; утилизация смотрится по статусным переменным.
SET GLOBAL innodb_buffer_pool_size = 12 * 1024 * 1024 * 1024;
SHOW GLOBAL STATUS LIKE 'Innodb_buffer_pool_read%';
# read_requests растёт, а read_physical почти стоитДополнительно InnoDB ведёт change buffer для отложенного обновления вторичных индексов, doublewrite buffer против «полузаписей» при падении питания и undo-логи, обеспечивающие многоверсионность (MVCC). Именно undo-логи позволяют читающим запросам видеть старую версию строки, пока транзакция не завершена.
- Длинные транзакции раздувают undo-логи и давят на очистку бэкграунда.
- При резких просадках сначала смотрите iostat и buffer pool hit ratio.
- Загрузка пула после рестарта — норма: он снова заполняется горячими страницами.
20. Миграции схем: Flyway и Liquibase
Ручное изменение структуры БД на проде — источник ночных инцидентов. Инструменты миграций хранят скрипты версиями и применяют по порядку, фиксируя в таблице журналирования, что уже выполнено.
-- V1__create_users.sql
CREATE TABLE users (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
email VARCHAR(255) NOT NULL UNIQUE
);
-- V2__add_status.sql
ALTER TABLE users
ADD COLUMN status ENUM('active','blocked')
DEFAULT 'active';- Никогда не редактируйте применённую миграцию — только новый файл версии.
- Деструктивные изменения (DROP) выносите в отдельный релиз и проверяйте на копии.
- Гоняйте миграции в CI на пустой базе — так проверяется воспроизводимость.
21. Целостность: внешние ключи и CHECK
Внешний ключ гарантирует, что ссылка на другую таблицу не «повиснет». Кроме запрета сиротских записей, он управляет каскадами: при удалении родителя движок сам удалит, ограничит или обнулит дочерние строки.
CREATE TABLE orders (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
user_id BIGINT NOT NULL,
amount DECIMAL(10,2),
CONSTRAINT fk_orders_user
FOREIGN KEY (user_id) REFERENCES users(id)
ON DELETE RESTRICT
);| Действие | Поведение при удалении родителя |
|---|---|
| RESTRICT | удаление запрещено, пока есть ссылки |
| CASCADE | дочерние строки удаляются вместе |
| SET NULL | внешний ключ становится NULL |
С MySQL 8.0.16 работают и CHECK-ограничения: они проверяют не связи, а значения строки. Индексы под внешние ключи создаются автоматически, но наличие FK замедляет массовые вставки — на огромных таблицах связи иногда осознанно не заводят.