Работното натоварване на базата данни на MySQL се определя от броя на заявките, които обработва. Има няколко ситуации, в които може да възникне забавяне на MySQL. Първата възможност е, ако има някакви заявки, които не използват правилно индексиране. Когато една заявка не може да използва индекс, MySQL сървърът трябва да използва повече ресурси и време, за да обработи тази заявка. Чрез наблюдение на заявки имате възможността да определите SQL код, който е основната причина за забавяне, и да го коригирате, преди цялостната производителност да се влоши.
В тази публикация в блога ще подчертаем функцията Query Outlier, налична в ClusterControl, и ще видим как тя може да ни помогне да подобрим производителността на базата данни. Като цяло ClusterControl извършва извадка от MySQL заявка по два начина:
- Извличане на заявките от схемата за ефективност (препоръчително ).
- Разбиране на съдържанието на MySQL Slow Query.
Ако схемата на производителност е деактивирана, ClusterControl по подразбиране ще използва дневника за бавни заявки. За да научите повече за това как ClusterControl изпълнява това, вижте тази публикация в блога, Как да използвате ClusterControl Query Monitor за MySQL, MariaDB и Percona Server.
Какво са отклоненията на заявката?
Отклонение е заявка, която отнема повече време от нормалното време за заявка от този тип. Не приемайте това буквално като "лошо написани" заявки. Трябва да се третира като потенциални неоптимални често срещани заявки, които могат да бъдат подобрени. След няколко проби и когато ClusterControl има достатъчно статистически данни, той може да определи дали латентността е по-висока от нормалното (2 сигми + средно_време_за_въпрос), тогава това е извънредно и ще бъде добавено към отклонението на заявката.
Тази функция зависи от функцията Топ заявки. Ако наблюдението на заявки е активирано и най-популярните заявки са уловени и попълнени, отклоненията на заявката ще ги обобщят и ще осигурят филтър въз основа на времеви печат. За да видите списъка със заявки, които изискват внимание, отидете на ClusterControl -> Query Monitor -> Query Outliers и трябва да видите някои изброени заявки (ако има такива):
Както можете да видите от екранната снимка по-горе, отклоненията са основно заявки, които отне поне 2 пъти повече от средното време за заявка. Първо, първият запис, средното време е 34,41 ms, докато времето за заявка на отклонения е 140 ms (повече от 2 пъти по-високо от средното време). По същия начин, за следващите записи колоните „Време на заявка“ и „Ср. време на заявка“ са две важни неща, за да оправдаят неизпълненията на конкретна извънредна заявка.
Сравнително лесно е да се намери модел на конкретна извънредна заявка, като се разгледа по-голям период от време, например преди седмица, както е подчертано на следната екранна снимка:
Като щракнете върху всеки ред, можете да видите пълната заявка, която наистина помага да се определи и разбере проблема, както е показано в следващия раздел.
Коригиране на отклоненията на заявката
За да коригираме отклоненията, трябва да разберем естеството на заявката, механизма за съхранение на таблиците, версията на базата данни, типа на клъстериране и колко въздействаща е заявката. В някои случаи извънредната заявка всъщност не влошава цялостната производителност на базата данни. Както в този пример, видяхме, че заявката се откроява през цялата седмица и това беше единственият тип заявка, която беше уловена, така че вероятно е добра идея да коригирате или подобрите тази заявка, ако е възможно.
Както в нашия случай, извънредната заявка е:
SELECT i2l.country_code AS country_code, i2l.country_name AS country_name
FROM ip2location i2l
WHERE (i2l.ip_to >= INET_ATON('104.144.171.139')
AND i2l.ip_from <= INET_ATON('104.144.171.139'))
LIMIT 1
OFFSET 0;
И резултатът от заявката е:
+--------------+---------------+
| country_code | country_name |
+--------------+---------------+
| US | United States |
+--------------+---------------+
Използване на EXPLAIN
Заявката е заявка за избор на диапазон само за четене, за да се определи информацията за географското местоположение на потребителя (код на държавата и име на държавата) за IP адрес в таблица ip2location. Използването на израза EXPLAIN може да ни помогне да разберем плана за изпълнение на заявката:
mysql> EXPLAIN SELECT i2l.country_code AS country_code, i2l.country_name AS country_name
FROM ip2location i2l
WHERE (i2l.ip_to>=INET_ATON('104.144.171.139')
AND i2l.ip_from<=INET_ATON('104.144.171.139'))
LIMIT 1 OFFSET 0;
+----+-------------+-------+------------+-------+--------------------------------------+-------------+---------+------+-------+----------+------------------------------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------+------------+-------+--------------------------------------+-------------+---------+------+-------+----------+------------------------------------+
| 1 | SIMPLE | i2l | NULL | range | idx_ip_from,idx_ip_to,idx_ip_from_to | idx_ip_from | 5 | NULL | 66043 | 50.00 | Using index condition; Using where |
+----+-------------+-------+------------+-------+--------------------------------------+-------------+---------+------+-------+----------+------------------------------------+
Заявката се изпълнява със сканиране на диапазон на таблицата с помощта на индекс idx_ip_from с 50% потенциални редове (филтрирани).
Правила машина за съхранение
Разглеждайки структурата на таблицата на ip2location:
mysql> SHOW CREATE TABLE ip2location\G
*************************** 1. row ***************************
Table: ip2location
Create Table: CREATE TABLE `ip2location` (
`ip_from` int(10) unsigned DEFAULT NULL,
`ip_to` int(10) unsigned DEFAULT NULL,
`country_code` char(2) COLLATE utf8_bin DEFAULT NULL,
`country_name` varchar(64) COLLATE utf8_bin DEFAULT NULL,
KEY `idx_ip_from` (`ip_from`),
KEY `idx_ip_to` (`ip_to`),
KEY `idx_ip_from_to` (`ip_from`,`ip_to`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin
Тази таблица е базирана на базата данни за IP2location и рядко се актуализира/записва, обикновено само на първия ден от календарния месец (препоръчан от доставчика). Така че една от опциите е да конвертирате таблицата в MyISAM (MySQL) или Aria (MariaDB) механизъм за съхранение с фиксиран формат на ред, за да получите по-добра производителност само за четене. Имайте предвид, че това е приложимо само ако работите на MySQL или MariaDB самостоятелно или с репликация. При репликацията на клъстер и група на Galera, моля, придържайте се към механизма за съхранение на InnoDB (освен ако не знаете какво правите).
Както и да е, за да конвертирате таблицата от InnoDB в MyISAM с фиксиран формат на ред, просто изпълнете следната команда:
ALTER TABLE ip2location ENGINE=MyISAM ROW_FORMAT=FIXED;
При нашето измерване, с 1000 теста за произволно търсене на IP адрес, производителността на заявката се подобри с около 20% с MyISAM и фиксиран формат на ред:
- Средно време (InnoDB):21,467823 ms
- Средно време (MyISAM Fixed):17,175942 ms
- Подобрение:19,992157565301 %
Можете да очаквате този резултат да бъде веднага след промяна на таблицата. Не е необходима промяна на по-високото ниво (приложение/балансиране на натоварването).
Настройка на заявката
Друг начин е да проверите плана на заявката и да използвате по-ефективен подход за по-добър план за изпълнение на заявка. Същата заявка може да бъде написана и с помощта на подзаявка, както е посочено по-долу:
SELECT `country_code`, `country_name` FROM
(SELECT `country_code`, `country_name`, `ip_from`
FROM `ip2location`
WHERE ip_to >= INET_ATON('104.144.171.139')
LIMIT 1)
AS temptable
WHERE ip_from <= INET_ATON('104.144.171.139');
Настроената заявка има следния план за изпълнение на заявка:
mysql> EXPLAIN SELECT `country_code`,`country_name` FROM
(SELECT `country_code`, `country_name`, `ip_from`
FROM `ip2location`
WHERE ip_to >= INET_ATON('104.144.171.139')
LIMIT 1)
AS temptable
WHERE ip_from <= INET_ATON('104.144.171.139');
+----+-------------+--------------+------------+--------+---------------+-----------+---------+------+-------+----------+-----------------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+--------------+------------+--------+---------------+-----------+---------+------+-------+----------+-----------------------+
| 1 | PRIMARY | <derived2> | NULL | system | NULL | NULL | NULL | NULL | 1 | 100.00 | NULL |
| 2 | DERIVED | ip2location | NULL | range | idx_ip_to | idx_ip_to | 5 | NULL | 66380 | 100.00 | Using index condition |
+----+-------------+--------------+------------+--------+---------------+-----------+---------+------+-------+----------+-----------------------+
Използвайки подзаявка, можем да оптимизираме заявката, като използваме производна таблица, която се фокусира върху един индекс. Заявката трябва да върне само 1 запис, където стойността на ip_to е по-голяма или равна на стойността на IP адреса. Това позволява на потенциалните редове (филтрирани) да достигнат 100%, което е най-ефективно. След това проверете дали ip_from е по-малък или равен на стойността на IP адреса. Ако е така, тогава трябва да намерим записа. В противен случай IP адресът не съществува в таблицата ip2location.
При нашето измерване ефективността на заявката се подобри с около 99% с помощта на подзаявка:
- Средно време (InnoDB + сканиране на диапазон):22,87112 ms
- Средно време (InnoDB + подзаявка):0,14744 ms
- Подобрение:99,355344207017 %
С горната оптимизация можем да видим време за изпълнение на заявка под милисекунда на този тип заявка, което е огромно подобрение, като се има предвид, че предишното средно време е 22 ms. Трябва обаче да направим някои модификации на по-високото ниво (приложение/балансиране на натоварването), за да се възползваме от тази настроена заявка.
Поправка или пренаписване на заявка
Поправете приложенията си, за да използват настроената заявка или пренапишете извънредната заявка, преди да стигне до сървъра на базата данни. Можем да постигнем това, като използваме MySQL балансьор на натоварването като ProxySQL (правила за заявки) или MariaDB MaxScale (филтър за пренаписване на изявления) или като използваме приставката за MySQL Query Rewriter. В следващия пример ние използваме ProxySQL пред нашия клъстер от база данни и можем просто да създадем правило за пренаписване на по-бавната заявка в по-бърза, например:
Запазете правилото за заявка и наблюдавайте страницата с отклонения на заявката в ClusterControl. Тази корекция очевидно ще премахне извънредните заявки от списъка, след като правилото за заявка бъде активирано.
Заключение
Отклоненията на заявки са проактивен инструмент за наблюдение на заявки, който може да ни помогне да разберем и коригираме проблема с производителността, преди той да излезе извън контрол. Тъй като приложението ви расте и става все по-взискателно, този инструмент може да ви помогне да поддържате прилична производителност на базата данни по пътя.