Биз жөнүндөБлогБайланыш
Маалымат базасы2015-ж., 14-сентябрь 4 мин 10

MySQL суроо-талаптарын кантип тездетүү керек: EXPLAIN жана индекстер (2015)

AunimedaAunimeda
📋 Мазмуну

MySQL суроо-талаптарын кантип тездетүү керек: EXPLAIN жана индекстер (2015)

Кыскача: Жай суроо-талапты EXPLAIN менен текшериңиз. Эгер type: ALL (толук таблицаны сканерлөө) же rows: 100000+ болсо — индекс керек. CREATE INDEX idx_name ON table(column) кошуп, EXPLAIN'ди кайра иштетиңиз. type: ref же range болуп калышы керек. Биздин мисалда: 8 секунд → 40 мс.


Реалдуу мисал: эмне болду

2015-жылы бир кардарыбыздын онлайн-дүкөнү жайлай баштады. Заказдар тизмеси жүклөнүп жатканда 7–10 секунд күтүү болчу. 50,000 заказ болгон маалымат базасы.

-- Проблемалуу суроо-талап
SELECT o.*, u.name as customer_name, u.phone
FROM orders o
JOIN users u ON u.id = o.user_id
WHERE o.status = 'pending'
  AND o.created_at >= '2015-09-01'
ORDER BY o.created_at DESC
LIMIT 20;

-- Убакыт: 7.8 секунд

Шаг 1: EXPLAIN менен диагностика

EXPLAIN 
SELECT o.*, u.name, u.phone
FROM orders o
JOIN users u ON u.id = o.user_id  
WHERE o.status = 'pending'
  AND o.created_at >= '2015-09-01'
ORDER BY o.created_at DESC
LIMIT 20;
+----+-------------+-------+------+---------------+------+---------+------+--------+-----------------------------+
| id | select_type | table | type | possible_keys | key  | key_len | ref  | rows   | Extra                       |
+----+-------------+-------+------+---------------+------+---------+------+--------+-----------------------------+
|  1 | SIMPLE      | o     | ALL  | NULL          | NULL | NULL    | NULL | 48923  | Using where; Using filesort |
|  1 | SIMPLE      | u     | ALL  | NULL          | NULL | NULL    | NULL | 12400  |                             |
+----+-------------+-------+------+---------------+------+---------+------+--------+-----------------------------+

Эмне билдирет:

  • type: ALL — толук таблицаны сканерлөө (эң жаман)
  • rows: 48923 — 49 миң жолду карайт, 20 гана кайтарат
  • Using filesort — ORDER BY үчүн дискте сорттоо
  • key: NULL — эч кандай индекс колдонулган жок

Шаг 2: Туура индекс кошуу

-- Суроо-талаптагы WHERE шарттарын талдоо:
-- WHERE o.status = 'pending'      → status боюнча
-- AND o.created_at >= '2015-09-01' → created_at боюнча
-- ORDER BY o.created_at DESC       → ошол эле created_at

-- Составной индекс: алгач тең тиңдеген мамыча, анан диапазондук
CREATE INDEX idx_status_created ON orders(status, created_at);

-- users таблицасы: id колонкасы (JOIN'да колдонулат)
-- PRIMARY KEY болушу керек — текшерүү:
SHOW CREATE TABLE users;
-- Эгер PRIMARY KEY(id) бар болсо — кошумча индекс керек эмес

Шаг 3: EXPLAIN кайра текшерүү

EXPLAIN 
SELECT o.*, u.name, u.phone
FROM orders o
JOIN users u ON u.id = o.user_id  
WHERE o.status = 'pending'
  AND o.created_at >= '2015-09-01'
ORDER BY o.created_at DESC
LIMIT 20;
+----+-------------+-------+-------+-------------------+-------------------+---------+--------+------+-------+
| id | select_type | table | type  | possible_keys     | key               | key_len | rows   | Extra |
+----+-------------+-------+-------+-------------------+-------------------+---------+--------+------+-------+
|  1 | SIMPLE      | o     | range | idx_status_created| idx_status_created| 207     | 243    |       |
|  1 | SIMPLE      | u     | eq_ref| PRIMARY           | PRIMARY           | 4       | 1      |       |
+----+-------------+-------+-------+-------------------+-------------------+---------+--------+------+-------+

Жакшырды:

  • type: range — индекс диапазонду колдонот (жакшы)
  • rows: 243 — 243 жол гана (48,923 эмес)
  • Using filesort жок — ORDER BY индекс аркылуу

Убакыт: 7.8 секунд → 38 мс (200 эсе тез!)


Slow Query Log: жай суроо-талаптарды табуу

# /etc/mysql/my.cnf
[mysqld]
slow_query_log         = 1
slow_query_log_file    = /var/log/mysql/slow.log
long_query_time        = 1  # 1 секунддан жай суроо-талаптарды жаз
log_queries_not_using_indexes = 1
sudo service mysql restart

# Slow log'ду карап чыгуу
tail -f /var/log/mysql/slow.log

# mysqldumpslow менен суммарлоо
mysqldumpslow -s t -t 10 /var/log/mysql/slow.log
# -s t: убакыт боюнча сортировка
# -t 10: эң жай 10 суроо-талап

Кеңири таралган индекс каталары

Ката 1: Функция ичинде колонка

-- ЖОЙ: индекс иштебейт
WHERE YEAR(created_at) = 2015

-- ТУУРА: диапазон колдон
WHERE created_at >= '2015-01-01' AND created_at < '2016-01-01'

Ката 2: OR шарты

-- ЖОЙ: OR'дагы индекс иштебеши мүмкүн
WHERE status = 'pending' OR user_id = 42

-- ТУУРА: UNION колдон
SELECT * FROM orders WHERE status = 'pending'
UNION
SELECT * FROM orders WHERE user_id = 42

Ката 3: LIKE менен башында %

-- ЖОЙ: индекс иштебейт
WHERE name LIKE '%алматы%'

-- ТУУРА: FULLTEXT INDEX колдон
ALTER TABLE articles ADD FULLTEXT INDEX ft_content(title, body);
SELECT * FROM articles WHERE MATCH(title, body) AGAINST('алматы' IN BOOLEAN MODE);

INDEX EXPLAIN типтерин түшүнүү

type Маанисы Баасы
ALL Толук таблица сканери ЭН ЖАМАН
index Толук индекс сканери Жаман
range Индекс диапазону Жакшы
ref Тиңдеме боюнча индекс Жакшы
eq_ref Уникалдуу индекс (JOIN) Өтө жакшы
const Бир жол (PRIMARY KEY) ЭН ЖАХШы

Индекс орнотулгандан кийинки мониторинг

-- Кайсы индекстер колдонулат, кайсысы колдонулбайт
SELECT 
    table_name,
    index_name,
    stat_name,
    stat_value
FROM mysql.innodb_index_stats
WHERE database_name = 'myshop'
ORDER BY table_name, index_name;

-- Колдонулбаган индекстерди табуу (MySQL 5.6+)
-- performance_schema.table_io_waits_summary_by_index_usage
SELECT object_schema, object_name, index_name
FROM performance_schema.table_io_waits_summary_by_index_usage
WHERE index_name IS NOT NULL
  AND count_star = 0
ORDER BY object_schema, object_name;

Колдонулбаган индекс — бекер жер жана INSERT/UPDATE убактысын жайлатат. Бар болгон индекстерди да аудиттен өткөрүү керек.

Ошондой эле окуңуз

Vue.js менен биринчи долбоор: Бишкектеги тажрыйба (2016)aunimeda
Frontend

Vue.js менен биринчи долбоор: Бишкектеги тажрыйба (2016)

Vue.js 2.0 2016-жылдын октябрь айында чыкты. React'ка салыштырмалуу жеңилирек үйрөнүлгөн. Биз Бишкектеги бир кардар үчүн онлайн-дүкөндүн себет бөлүмүн Vue.js менен жасадык. Components, reactivity, Vuex — реалдуу мисалдар менен.

Express.js менен REST API сервер кантип жасоо: нөлдөн production'го чейин (2015)aunimeda
Backend

Express.js менен REST API сервер кантип жасоо: нөлдөн production'го чейин (2015)

Node.js 4 LTS + Express.js 4 — 2015-жылда PHP'га альтернатива катары пайда болду. Биз Бишкекте мобилдик тиркеме үчүн API сервер жасадык. Роутинг, middleware, валидация, JWT авторизация, MySQL — бардыгы бир жерде. Иштеген код мисалдары.

React Native менен биринчи мобилдик тиркеме жасоо: Бишкек тажрыйбасы (2015)aunimeda
Мобилдик иштеп чыгуу

React Native менен биринчи мобилдик тиркеме жасоо: Бишкек тажрыйбасы (2015)

React Native 2015-жылдын март айында Facebook тарабынан жарыяланды. Биз iOS жана Android үчүн бир эле код жазуу мүмкүнчүлүгүнө ишандык. Биринчи production тиркемебизди 8 апта ичинде жасадык. Реалдуу код, реалдуу проблемалар, реалдуу жыйынтыктар.

Бизнесиңизге IT иштеп чыгуу керекпи?

Веб-сайттарды, мобилдик тиркемелерди жана AI чечимдерин иштеп чыгабыз. Акысыз консультация.

Консультация алуу Бардык макалалар