Мне нужна помощь, чтобы выяснить проблему с производительностью. База данных, содержащая одну таблицу с растущим числом METAR (авиационные метеорологические сводки), замедляется после появления около 8 миллионов записей. Это несмотря на использование индексов. Производительность можно восстановить, перестроив индексы, но это очень медленно и переводит базу данных в автономный режим, поэтому я прибег к простому удалению таблицы и ее повторному созданию (потеря данных за последние несколько недель).
Поведението же самое, выполняется ли запрос, пытаясь получить фактический метар, или выполняется простой select count(*)
.
Синтаксис создания таблицы следующий:
CREATE TABLE `metars` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`tstamp` timestamp NULL DEFAULT NULL,
`metar` varchar(255) DEFAULT NULL,
`icao` char(7) DEFAULT NULL,
`qnh` int(11) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `timestamp` (`tstamp`),
KEY `icao` (`icao`),
KEY `qnh` (`qnh`),
KEY `metar` (`metar`)
) ENGINE=InnoDB AUTO_INCREMENT=812803050 DEFAULT CHARSET=latin1;
Примерно до8 миллионов записей, select count(*)
возвращается примерно за 500 мс. Затем он постепенно увеличивается, в настоящее время снова на 14 миллионов записей, отсчет занимает от 3 до 30 секунд. Я был удивлен, увидев, что при объяснении запроса количества он использует временную метку в качестве индекса, а не первичный ключ. При использовании первичного ключа это может занять всего несколько мс, чтобы вернуть количество записей:
mysql> explain select count(*) from metars;
+----+-------------+--------+-------+---------------+-----------+---------+------+----------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+--------+-------+---------------+-----------+---------+------+----------+-------------+
| 1 | SIMPLE | metars | index | NULL | timestamp | 5 | NULL | 14693048 | Using index |
+----+-------------+--------+-------+---------------+-----------+---------+------+----------+-------------+
1 row in set (0.00 sec)
Заставить его использовать первичный индекс еще медленнее:
mysql> select count(*) from metars use index(PRIMARY);
+----------+
| count(*) |
+----------+
| 14572329 |
+----------+
1 row in set (37.87 sec)
Как ни странно, типичный запрос варианта использования состоит в том, чтобы получить погоду для аэропорта, ближайшего к определенному моменту времени, который продолжает работать очень хорошо, несмотря на то, что он является более сложным, чем простой подсчет:
mysql> SELECT qnh, metar from metars WHERE icao like 'KLAX' ORDER BY ABS(TIMEDIFF(tstamp, STR_TO_DATE('2019-10-10 00:00:00', '%Y-%m-%d %H:%i:%s'))) LIMIT 0,1;
+------+-----------------------------------------------------------------------------------------+
| qnh | metar |
+------+-----------------------------------------------------------------------------------------+
| 2980 | KLAX 092353Z 25012KT 10SM FEW015 20/14 A2980 RMK AO2 SLP091 T02000139 10228 20200 56007 |
+------+-----------------------------------------------------------------------------------------+
1 row in set (0.01 sec)
Что яздесь делаешь неправильно?