Задать вопрос
Tkreks
@Tkreks
Системный инженер

Большое кол-во записей в секунду в MySQL. Как читать последний порядковый номер столбца и добавлять к нему +1 при записи?

Здравствуйте, не знаю как правильно сформулировать заголовок запроса. Постараюсь отразить в деталях.
Есть некая абстрактная БД на mysql, в которых я по сути заполняю лишь одну колонку - result.
Схема таблицы
66b6149a94c0a648318794.png

Где id = Auto Increment , остальные колонки заполняются инсертами.
Есть некоторое устройство (на самом деле таких устройств может быть десятки), которое может генерировать данные с периодичностью 0.001сек. Периодичность меняется, но я закладываю максимальную скорость генерации.
C устройства передаются данные, которые заполняются в колонки (sessid и result)
Само устройство пишет не напрямую в базу, а передаёт данные в обработчик, на котором я реализовал следующую логику -
->Поступают данные с устройства ->

->выполняется проверка наличия sessid в базе
SELECT
	table.serialnumb
FROM
	table
WHERE
	sessid = $sess.id$
ORDER BY
	base.table DESC
LIMIT 1

Таким образом я получаю наибольшее значение serialnumb для данного sessid->

->если не найдено выполняется -
INSERT INTO `base`.`table`(`sessid`, `serialnumb`, `result`, `numnum`) VALUES ('$sess.id', 0, '0', $numnum)
и отправляется заново на проверку наличия sessid в базе->

->Если найдено - выполняю проверку уникальность result в данном sessid (не должно быть двух одинаковых result для одного sessid). Повторные значения result отбрасываю. ->

->Уникальное значение - беру serialnumb +1 и делаю инсерт
INSERT INTO `base`.`table`(`sessid`, `serialnumb`, `result`, `numnum`) VALUES ('$sess.id$', $sess.newlastnum$, '$rand$', $numnum$)

Собственно, я продебажил на разном железе, но в рамках ВМ (на вм стоит mysql и на отдельной вм стоит обработчик на node) у меня получилось так
Intel Platinum 8380 + ddr4
Самый толстый запрос усреднённо 0.04 сек занимает (select с 100 тыс.строк данных)
Ryzen 7 7800x3D + ddr5
тот же запрос 0.035 сек
Тестовый стенд intel xeon gold 6130
тот же запрос усредненно 0.1 сек

Проблема в том, что serialnumb должен быть уникальный в рамках sessid. Чего не получается добиться при большой интенсивности запросов.
Проблемка
66b62718633f9254116306.png

Причина-следственная связь ясна, из за большого наплыва информации select отрабатывает раньше у части запросов, в связи с чем отдается устаревший serialnumb, в связи с чем один serialnumb прописывается для нескольких запросов.
В итоговом решение - железо будет использовать энергоэффективное, соответственно вариант с железом отметаем.
Можно оптимизировать запросы + оптимизировать саму БД (т.к. она она стоковая без тюнинга mariadb 10.5) - но не думаю что приведет к исключению проблемы.
Как решение, вижу такой способ. Добавление всех записей во временную таблицу, Где будет 3 колонки (id (auto incremet), sessid, result) и далее уже перенос в актуальную таблицу. Но это может дать лаг при анализе данных на frontend, чего хотелось бы избежать. По этой же причине не хотелось бы делать задержку ожидания на обработчике, (тогда там memory может вспухнуть если будет гигантская очередь).
Подскажите, какие способы оптимизации или решения моего вопроса воспользовались бы Вы? Может я где-то нарушил логическую цепочку ?
  • Вопрос задан
  • 134 просмотра
Подписаться 1 Сложный Комментировать
Решение пользователя Rsa97 К ответам на вопрос (2)
Rsa97
@Rsa97
Для правильного вопроса надо знать половину ответа
Какой-то бред.
1. Составной ключ по автоинкрементному полю и обычному смысла не имеет, поскольку автоинкрементное поле id всегда уникально, то добавление к нем sessid ничего, кроме торможения, не добавит.
2. Делать какую-то отдельную проверку на уникальность result внутри sessid смысла не имеет. Достаточно сделать уникальный составной ключ (sessid, result) и использовать INSERT IGNORE.
3. Отдельное поле serialnumb абсолютно не нужно. Выборку всегда можно отсортировать через ORDER BY id и пронумеровать через оконные функции.
Ответ написан