Davion Posted June 10, 2019 · Report post Коллеги дайте совет. Есть Freeradius где абонентам выделяются IP адреса используя следующие запросы. allocate_find = "\ SELECT framedipaddress FROM ${ippool_table} \ WHERE pool_name = 'test' \ AND ( (username = '%{User-Name}') OR (expiry_time < NOW() OR expiry_time IS NULL) ) \ ORDER BY \ (username <> '%{User-Name}'), \ expiry_time \ LIMIT 1 \ FOR UPDATE" allocate_update = "\ UPDATE ${ippool_table} \ SET \ nasipaddress = '%{NAS-IP-Address}', pool_key = '${pool_key}', \ callingstationid = '%{Calling-Station-Id}', \ username = '%{User-Name}', expiry_time = NOW() + INTERVAL ${lease_duration} SECOND \ WHERE framedipaddress = '%I'" Если использовать mariadb 10.3 + InnoDB(myisam не подходит из за необходимости транзакций) то при тестирование база быстро загибается, в процессах повисают SELECT. При использование Postgres из коробки все летает, все достаточно быстро обрабатывает. После небольшого тюнинга производительность вырасла еще в два раза... Пробовал использовать MySQL с функцией построчной блокировки FOR UPDATE SKIP LOCK производительность MySQL выросла, но всеравно в разы хуже чем у Postgresql Неужели у MySQL+InnoDB все так плохо? Кто какие решения использует? Вставить ник Quote Ответить с цитированием Share this post Link to post Share on other sites More sharing options...
alibek Posted June 10, 2019 · Report post MySQL при правильном использовании даёт неплохую производительность. Какие-то гуглосервисы на нем даже работают. Но это нужно анализировать запросы, создавать индексы, настраивать БД и сервер, вообщем погружаться довольно глубоко в DBA. Если с Postgre все хорошо, то его и используйте, он из коробки работает лучше, чем MySQL из коробки. Вставить ник Quote Ответить с цитированием Share this post Link to post Share on other sites More sharing options...
Davion Posted June 10, 2019 · Report post Да уже как только и индексы не крутил, и различные тюнинги, всеравно просто жо... Интересно как у других оно, наверняка уже набили шишки. Вставить ник Quote Ответить с цитированием Share this post Link to post Share on other sites More sharing options...
jffulcrum Posted June 10, 2019 · Report post https://github.com/major/MySQLTuner-perl умеет выдать кучу инфы с подсказками, что не так. Вставить ник Quote Ответить с цитированием Share this post Link to post Share on other sites More sharing options...
Davion Posted June 10, 2019 · Report post 44 минуты назад, jffulcrum сказал: https://github.com/major/MySQLTuner-perl умеет выдать кучу инфы с подсказками, что не так. Это было проверено первым) когда у тебя 10 тыс клиентов подключается, все просто умирает) Вставить ник Quote Ответить с цитированием Share this post Link to post Share on other sites More sharing options...
NewUse Posted June 10, 2019 · Report post индекс по округлённому до минут expiry_time создать, индекс по username, возможно, индекс по framedipaddress(не понимаю как select for update тут может/должно работать, если не работает, то нужен индекс, если работает, то не нужен), остальные индексы грохнуть. Вставить ник Quote Ответить с цитированием Share this post Link to post Share on other sites More sharing options...
Davion Posted June 10, 2019 · Report post 8 минут назад, NewUse сказал: индекс по округлённому до минут expiry_time создать, индекс по username, возможно, индекс по framedipaddress(не понимаю как select for update тут может/должно работать, если не работает, то нужен индекс, если работает, то не нужен), остальные индексы грохнуть. Так и сделано, правда индекс еще и по адресу. Вставить ник Quote Ответить с цитированием Share this post Link to post Share on other sites More sharing options...
NewUse Posted June 10, 2019 · Report post выкиньте лишний индекс, analyze для таблицы/индексов делали? Вставить ник Quote Ответить с цитированием Share this post Link to post Share on other sites More sharing options...
NewUse Posted June 10, 2019 · Report post Проверьте, не проявляется ли у Вас этот баг: https://bugs.mysql.com/bug.php?id=67745 т.е. лок идёт более чем на одну строчку. 25 минут назад, Davion сказал: правда индекс еще и по адресу. покажите индексы. Вставить ник Quote Ответить с цитированием Share this post Link to post Share on other sites More sharing options...
Davion Posted June 11, 2019 · Report post 10 часов назад, NewUse сказал: Проверьте, не проявляется ли у Вас этот баг: https://bugs.mysql.com/bug.php?id=67745 т.е. лок идёт более чем на одну строчку. покажите индексы. Текущая конфигурация индексов Create Table CREATE TABLE `radippool` ( `id` int(11) unsigned NOT NULL AUTO_INCREMENT, `pool_name` varchar(30) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL, `framedipaddress` varchar(15) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL DEFAULT '', `nasipaddress` varchar(15) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL DEFAULT '', `calledstationid` varchar(30) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL, `callingstationid` varchar(30) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL, `expiry_time` datetime DEFAULT NULL, `username` varchar(64) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL DEFAULT '', `pool_key` varchar(30) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL, PRIMARY KEY (`id`), KEY `pool_name` (`pool_name`,`username`,`expiry_time`,`framedipaddress`), KEY `pool_name_2` (`pool_name`,`expiry_time`,`username`,`framedipaddress`) ) ENGINE=InnoDB AUTO_INCREMENT=70092 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci Для отсутствия блокировки таблицы, используется MySQL 8 c SKIP LOCK allocate_find = "\ SELECT framedipaddress FROM ${ippool_table} \ WHERE pool_name = 'test' \ AND ( (username = '%{User-Name}') OR (expiry_time < NOW() OR expiry_time IS NULL) ) \ ORDER BY \ (username <> '%{User-Name}'), \ expiry_time \ LIMIT 1 \ FOR UPDATE SKIP LOCKED" Вставить ник Quote Ответить с цитированием Share this post Link to post Share on other sites More sharing options...
NewUse Posted June 11, 2019 · Report post Цитата show indexes from radippool; покажите. 2 часа назад, Davion сказал: Для отсутствия блокировки таблицы, используется MySQL 8 c SKIP LOCK не надо костылей, проверьте сколь без скип лок блокируется при Вашем запросе, скорее всего в нём проблема и надо его менять. 2 часа назад, Davion сказал: KEY `pool_name` (`pool_name`,`username`,`expiry_time`,`framedipaddress`), я уже не помню синтексиса вывода mysql, но зачем у Вас индекс составной, если это, конечно, индекс. Вставить ник Quote Ответить с цитированием Share this post Link to post Share on other sites More sharing options...
jffulcrum Posted June 11, 2019 · Report post @Davion 3 часа назад, Davion сказал: allocate_find = "\ SELECT framedipaddress FROM ${ippool_table} \ WHERE pool_name = 'test' \ AND ( (username = '%{User-Name}') OR (expiry_time < NOW() OR expiry_time IS NULL) ) \ ORDER BY \ (username <> '%{User-Name}'), \ expiry_time \ LIMIT 1 \ FOR UPDATE SKIP LOCKED" Сделайте EXPLAIN для данного запроса, сразу увидите, есть ли индексы и работают ли он для данного запроса. Вставить ник Quote Ответить с цитированием Share this post Link to post Share on other sites More sharing options...
Davion Posted June 11, 2019 · Report post 2 часа назад, jffulcrum сказал: @Davion Сделайте EXPLAIN для данного запроса, сразу увидите, есть ли индексы и работают ли он для данного запроса. +----+-------------+-----------+------------+------+-----------------------+-----------+---------+-------+-------+----------+------------------------------------------+ | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra | +----+-------------+-----------+------------+------+-----------------------+-----------+---------+-------+-------+----------+------------------------------------------+ | 1 | SIMPLE | radippool | NULL | ref | pool_name,pool_name_2 | pool_name | 92 | const | 28978 | 46.00 | Using where; Using index; Using filesort | +----+-------------+-----------+------------+------+-----------------------+-----------+---------+-------+-------+----------+------------------------------------------+ 1 row in set, 1 warning (0,00 sec) Все ок. 2 часа назад, NewUse сказал: покажите. не надо костылей, проверьте сколь без скип лок блокируется при Вашем запросе, скорее всего в нём проблема и надо его менять. я уже не помню синтексиса вывода mysql, но зачем у Вас индекс составной, если это, конечно, индекс. mysql> show indexes from radippool; +-----------+------------+-------------+--------------+-----------------+-----------+-------------+----------+--------+------+------------+---------+---------------+---------+------------+ | Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment | Visible | Expression | +-----------+------------+-------------+--------------+-----------------+-----------+-------------+----------+--------+------+------------+---------+---------------+---------+------------+ | radippool | 0 | PRIMARY | 1 | id | A | 57731 | NULL | NULL | | BTREE | | | YES | NULL | | radippool | 1 | pool_name | 1 | pool_name | A | 1 | NULL | NULL | | BTREE | | | YES | NULL | | radippool | 1 | pool_name | 2 | username | A | 57731 | NULL | NULL | | BTREE | | | YES | NULL | | radippool | 1 | pool_name | 3 | expiry_time | A | 57731 | NULL | NULL | YES | BTREE | | | YES | NULL | | radippool | 1 | pool_name | 4 | framedipaddress | A | 57731 | NULL | NULL | | BTREE | | | YES | NULL | | radippool | 1 | pool_name_2 | 1 | pool_name | A | 1 | NULL | NULL | | BTREE | | | YES | NULL | | radippool | 1 | pool_name_2 | 2 | expiry_time | A | 12004 | NULL | NULL | YES | BTREE | | | YES | NULL | | radippool | 1 | pool_name_2 | 3 | username | A | 55087 | NULL | NULL | | BTREE | | | YES | NULL | | radippool | 1 | pool_name_2 | 4 | framedipaddress | A | 56460 | NULL | NULL | | BTREE | | | YES | NULL | +-----------+------------+-------------+--------------+-----------------+-----------+-------------+----------+--------+------+------------+---------+---------------+---------+------------+ Ну логично что блокируется вся таблица без SKIP LOCK Вставить ник Quote Ответить с цитированием Share this post Link to post Share on other sites More sharing options...
NewUse Posted June 11, 2019 (edited) · Report post не логично, судя по доке должны блокироваться только выбранные строки, а skip locked снимает это ограничение, в любом случае, я почти уверен, что не отрабатывает, limit, проверьте. Не вижу индекса по округлённому expiry_time, также не совсем понимаю, но похоже у Вас индексы составные, что в Вашем случае может сыграть в минус. общий объем таблицы в строках, сколько 1млн то хоть есть? Edited June 11, 2019 by NewUse Вставить ник Quote Ответить с цитированием Share this post Link to post Share on other sites More sharing options...
Davion Posted June 11, 2019 · Report post 38 минут назад, NewUse сказал: не логично, судя по доке должны блокироваться только выбранные строки, а skip locked снимает это ограничение, в любом случае, я почти уверен, что не отрабатывает, limit, проверьте. Не вижу индекса по округлённому expiry_time, также не совсем понимаю, но похоже у Вас индексы составные, что в Вашем случае может сыграть в минус. Были не составные разницы никакой. В MySQL 8.0.1 был введен модификатор SKIP LOCKED, использующийся для не детерминистического чтения из таблицы с пропуском строк, заблокированых другими пользователями. https://sqlinfo.ru/articles/info/41.html Вставить ник Quote Ответить с цитированием Share this post Link to post Share on other sites More sharing options...
NewUse Posted June 11, 2019 · Report post да, но это не совсем то, Если у Вас блокиррвалась и обновлялась только одна строка, то по идее влять серьёзно скип локед был не должен. так что проверяйте. Верните несоставные. Сделайте индекс с округлением, Вы не ответили по объёму таблицы. Если таблица маленькая, то причина в локах, надо тогда добиваться блокировки ровно одной строки на запрос(это к специалистам mysql обращаться надо на какой-нибудь sql ru) Вставить ник Quote Ответить с цитированием Share this post Link to post Share on other sites More sharing options...
Davion Posted June 11, 2019 · Report post Поигрался с индексами чуть удалось разогнать, но не сильно) 3 минуты назад, NewUse сказал: да, но это не совсем то, Если у Вас блокиррвалась и обновлялась только одна строка, то по идее влять серьёзно скип локед был не должен. так что проверяйте. Верните несоставные. Сделайте индекс с округлением, Вы не ответили по объёму таблицы. Если таблица маленькая, то причина в локах, надо тогда добиваться блокировки ровно одной строки на запрос(это к специалистам mysql обращаться надо на какой-нибудь sql ru) 60 тыс. записей Гугол не знае про округление индексов... Вставить ник Quote Ответить с цитированием Share this post Link to post Share on other sites More sharing options...
Davion Posted June 11, 2019 · Report post Удалось разогнать Total sent : 1936 Total retransmits : 7 Total succeeded : 1936 Total failed : 0 Total no reply : 0 Total time (s) : 73.341 Packets/s : 26 Response times: < 10 usec : 0 < 100 usec : 0 < msec : 0 < 10 msec : 0 < 0.1s : 0 < s : 32 < 10s : 1904 < 100s : 0 Но до Postgresql не дотягивает: Total sent : 1936 Total retransmits : 0 Total succeeded : 1936 Total failed : 0 Total no reply : 0 Total time (s) : 20.880 Packets/s : 93 Response times: < 10 usec : 0 < 100 usec : 0 < msec : 0 < 10 msec : 0 < 0.1s : 0 < s : 1936 < 10s : 0 < 100s : 0 Без SKIP LOCKED все в ступор впадает... Индексы сделал несоставные Вставить ник Quote Ответить с цитированием Share this post Link to post Share on other sites More sharing options...
Davion Posted June 11, 2019 · Report post Total sent : 1936 Total retransmits : 2 Total succeeded : 1936 Total failed : 0 Total no reply : 0 Total time (s) : 5.015 Packets/s : 386 Response times: < 10 usec : 0 < 100 usec : 0 < msec : 0 < 10 msec : 0 < 0.1s : 1810 < s : 124 < 10s : 2 < 100s : 0 Если expiry_time еще не истек, тогда все хорошо) Без SKIP LOCKED тоже все ок... Если expiretime истек, то все ступор. Вставить ник Quote Ответить с цитированием Share this post Link to post Share on other sites More sharing options...
Davion Posted June 11, 2019 · Report post проблема видимо в INDEX datetime Вставить ник Quote Ответить с цитированием Share this post Link to post Share on other sites More sharing options...
NewUse Posted June 11, 2019 (edited) · Report post 51 минуту назад, Davion сказал: Гугол не знае про округление индексов... похоже я это на постгресе делал, а не на мускуле, но сделайте тогда виртуальную колонку с округлен до минуты expiry_time , постройте индекс по ней, и в запросе используйте поиск по ней. не, всё ОК, всё умеет, только обрезку до минут или часов сделайте: https://use-the-index-luke.com/sql/where-clause/obfuscation/dates 39 минут назад, Davion сказал: Без SKIP LOCKED все в ступор впадает... сколько блокировок на один запрос select for update? Edited June 11, 2019 by NewUse добавил пример индекса по округлению Вставить ник Quote Ответить с цитированием Share this post Link to post Share on other sites More sharing options...
NewUse Posted June 11, 2019 · Report post 1 час назад, Davion сказал: 60 тыс. записей у Вас не должно быть запросов дольше 0.1 секунды, по крайней мере на Oracle среднее время выполнения было бы около 0.02с. Вставить ник Quote Ответить с цитированием Share this post Link to post Share on other sites More sharing options...
Tosha Posted June 11, 2019 · Report post 20 часов назад, Davion сказал: UPDATE ... WHERE framedipaddress = '%I'" Без индекса по framedipaddress это знатные грабли Выборка же в таком виде ничего кроме индекса по pool_name использовать не может - составной индекс при условии "OR" бесполезен Вставить ник Quote Ответить с цитированием Share this post Link to post Share on other sites More sharing options...
NewUse Posted June 11, 2019 · Report post у него select for update: не нужен индекс по framedipaddress при одной строке в выборке. Вставить ник Quote Ответить с цитированием Share this post Link to post Share on other sites More sharing options...
Tosha Posted June 11, 2019 · Report post select for update только блокировку ставит. Скорости исполнения апдейта он мало помогает. Имхо Вставить ник Quote Ответить с цитированием Share this post Link to post Share on other sites More sharing options...