Interview Questions

Databases

Редактировать на GitHub

Теоретические вопросы

Как настроить master-slave репликацию в mysql (кратко)?

Необходимы 2 сервера: master и slave.

  1. На обеих сервера устанавливаем сервер MySQL одинаковой версии.
  2. Включаем сервер базы данных на обеих серверах.
  3. Настраиваем master - в /etc/my.cnf устанавливаем слеюущие значения:
# выбираем ID сервера, произвольное число, лучше начинать с 1
server-id = 1
# путь к бинарному логу
log_bin = /var/log/mysql/mysql-bin.log
# название Вашей базы данных, которая будет реплицироваться
binlog_do_db = newdatabase

Перезапускаем сервер базы данных. 4. Подключаемся к master серверу, создаем пользователя и назначаем ему права для выполнения репликации.

mysql -u root -p <пароль root сервера БД>
GRANT REPLICATION SLAVE ON *.* TO 'slave_user'@'%' IDENTIFIED BY 'password';
FLUSH PRIVILEGES;
  1. На master сервере делаем дамп базы данных c блокировкой таблиц.
mysqldump -u root -p --lock-all-tables newdatabase > newdatabase.sql
  1. Переносим дамп базы на slave сервер, создаем базу данных с таким же именем и импортируем базу.
CREATE DATABASE newdatabase;
mysql -u root -p newdatabase < newdatabase.sql
  1. Настраиваем slave в /etc/my.cnf:
# ID Слейва, удобно выбирать следующим числом после Мастера
server-id = 2
# Путь к relay логу
relay-log = /var/log/mysql/mysql-relay-bin.log
# Путь к bin логу на Мастере
log_bin = /var/log/mysql/mysql-bin.log
# База данных для репликации
binlog_do_db = newdatabase

Перезапускаем сервер базы данных. 8. Запускаем репликацию на slave сервере.

CHANGE MASTER TO MASTER_HOST='10.10.0.1', MASTER_USER='slave_user', MASTER_PASSWORD='password',
MASTER_LOG_FILE = 'mysql-bin.000001', MASTER_LOG_POS = 107;
##Указанные значения мы берем из настроек Мастера
После этого запускаем репликацию на Слейве:
START SLAVE;
  1. Проверяем статус репликации:
SHOW SLAVE STATUSG

Какой тип базы данных использует Prometheus?

Prometheus использует TSDB (time series database).

Что такое VACUUM в PostgreSQL?

VACUUM высвобождает пространство, занимаемое «мёртвыми» кортежами. При обычных операциях PostgreSQL кортежи, удалённые или устаревшие в результате обновления, физически не удаляются из таблицы; они сохраняются в ней, пока не будет выполнена команда VACUUM. Таким образом, периодически необходимо выполнять VACUUM, особенно для часто изменяемых таблиц.

Без параметра команда VACUUM обрабатывает все таблицы в текущей базе данных, которые может очистить текущий пользователь. Если в параметре передаётся имя таблицы, VACUUM обрабатывает только эту таблицу.

Простая команда VACUUM (без FULL) только высвобождает пространство и делает его доступным для повторного использования. Эта форма команды может работать параллельно с обычными операциями чтения и записи таблицы, так она не требует исключительной блокировки. Однако освобождённое место не возвращается операционной системе (в большинстве случаев); оно просто остаётся доступным для размещения данных этой же таблицы. VACUUM FULL переписывает всё содержимое таблицы в новый файл на диске, не содержащий ничего лишнего, что позволяет возвратить неиспользованное пространство операционной системе. Эта форма работает намного медленнее и запрашивает исключительную блокировку для каждой обрабатываемой таблицы.

Практические вопросы

Мы знаем, что есть всего 7 записей с ticket_id=56412. Записей с ticket_id > 60000 нет, никаких символов перед 56412 нет. Как могла появиться разница в количестве? Опишите ваши действия.

По условию задачи:

  • SELECT count(*) FROM tickets_messages WHERE ticket_id=56412; возвращает 5 записей
  • SELECT count(*) FROM tickets_messages WHERE ticket_id LIKE '%56412'; возвращает 7 записей

Разница возникает из-за того, что в колонке ticket_id могут храниться данные разных типов (например, строка VARCHAR вместо INT).

  • В случае строгого сравнения ticket_id=56412 выбираются только записи, где значение строго равно числу 56412.
  • В случае LIKE '%56412' выбираются записи, где значение заканчивается на "56412", включая строки вроде:
    • '56412' (строка, совпадающая с числом),
    • 'abc56412',
    • '0056412'.

📌 Итог: 2 «лишние» записи — это строки, в которых ticket_id содержит 56412 как подстроку, но не равен числу 56412.

Что бы я сделал:

  1. Проверил тип поля ticket_id:
\d tickets_messages    -- в PostgreSQL
DESC tickets_messages; -- в MySQL
  1. Вывел все записи для проверки:
SELECT ticket_id FROM tickets_messages WHERE ticket_id LIKE '%56412';
  1. Нормализовал поле (привёл к числовому типу, если это действительно ID).

Какой из вопросов MySQL самый тяжелый? Расскажите как вы его выявили?

Данные по запросам:

  1. Запрос #1
    • Query_time: 2.18s
    • Rows_examined: 324,036
    • JOIN + сортировка + LIMIT 100.
  2. Запрос #2
    • Query_time: 9.25s
    • Rows_examined: 948,209
    • DELETE FROM phpbb_post_revisions WHERE post_id = …;
    • Очень долго для DELETE по одному post_id. Вероятнее всего нет индекса по post_id.
  3. Запрос #3
    • Query_time: 1.11s
    • Rows_examined: 521,597
    • JOIN + ORDER BY + LIMIT "бесконечный" (18446744073709551615). То есть фактически без LIMIT, что очень тяжело.
  4. Запрос #4
    • Query_time: 4.68s
    • Rows_examined: 2,457,916 (! много)
    • Тоже JOIN + ORDER BY + огромный список IN (…) + "бесконечный" LIMIT.

Самый тяжёлый:

👉 Запрос #2 (DELETE)

  • 9.25s (самое большое время выполнения)
  • почти миллион строк просмотрено для удаления всего одной записи. Это явный индикатор отсутствия индекса по post_id в таблице phpbb_post_revisions.

Как выявили:

  1. Взял slow-log.
  2. Сравнил Query_time и Rows_examined.
  3. Запрос #2 выделяется как самый тяжёлый (и по времени, и по неэффективности).

Как исправить:

  • Проверить индексы: SHOW CREATE TABLE phpbb_post_revisions\G
  • Если по post_id нет индекса → добавить: CREATE INDEX idx_post_id ON phpbb_post_revisions(post_id);
  • Перепроверить EXPLAIN: EXPLAIN DELETE FROM phpbb_post_revisions WHERE post_id = 10472158;

Последнее обновление: 7 окт. 2025 г., 08:07:55