Как использовать задержку вставки с движком InnoDB и использовать меньше соединений для операторов вставки?

10

Я работаю над приложением, которое включает в себя много записей в базе данных, примерно ~ 70% операций вставки и 30% операций чтения. Это соотношение также включает в себя обновления, которые я считаю одним чтением и одной записью. Через операторы вставки несколько клиентов вставляют данные в базу данных через оператор вставки ниже:

$mysqli->prepare("INSERT INTO `track` (user, uniq_name, ad_name, ad_delay_time ) values (?, ?, ?, ?)");

Вопрос в том, должен ли я использовать либо insert_delay, либо механизм mysqli_multi_query , потому что оператор вставки использует ~ 100% ЦП на сервере. Я использую движок InnoDB в своей базе данных, поэтому вставка с задержкой невозможна. Вставка на сервер ~ 36k / ч и чтение 99,89%, также я использую оператор SELECT, чтобы получить данные семь раз в одном запросе , этот запрос занимает 150 секунд на сервере для выполнения. Какую технику или механизм я могу использовать для этой задачи? Моя память сервера составляет 2 ГБ, я должен расширить память ?. Посмотрите на эту проблему, любые предложения будут благодарны мне.

Структура стола:

+-----------------+--------------+------+-----+-------------------+----------------+
| Field           | Type         | Null | Key | Default           | Extra          |
+-----------------+--------------+------+-----+-------------------+----------------+
| id              | int(11)      | NO   | PRI | NULL              | auto_increment |
| user            | varchar(100) | NO   |     | NULL              |                |
| uniq_name       | varchar(200) | NO   |     | NULL              |                |
| ad_name         | varchar(200) | NO   |     | NULL              |                |
| ad_delay_time   | int(11)      | NO   |     | NULL              |                |
| track_time      | timestamp    | NO   | MUL | CURRENT_TIMESTAMP |                |
+-----------------+--------------+------+-----+-------------------+----------------+

Состояние моей базы данных в настоящий момент показывает 41 тыс. Вставок (записей), что очень медленно для моей базы данных.

состояние базы данных

Shashank
источник
Можете ли вы дать определение таблицы? (все столбцы, типы данных и индексы)
ypercubeᵀᴹ
Можете ли вы дать краткий фрагмент своего, SHOW FULL PROCESSLISTкогда он берет 100% процессора? Сколько соединений вы разрешаете против того, сколько было взято за это время?
Дерек Дауни
Пожалуйста, запустите эти два запроса: SHOW GLOBAL VARIABLES LIKE 'innodb%';и SELECT VERSION();и отобразите их вывод.
RolandoMySQLDBA
Пожалуйста, укажите количество вставок в секунду, которое вы выполняете.
dabest1
Ваш код очень восприимчив к SQL-инъекции. Используйте подготовленные операторы и параметризованные значения.
Аарон Браун

Ответы:

11

Поскольку у вас есть больше записей, чем читает, я хотел бы рекомендовать следующее

Достойная настройка InnoDB будет ключевым

Буферный пул (размер innodb_buffer_pool_size )

Поскольку InnoDB не поддерживает INSERT DELAYED , использование большого пула буферов InnoDB - это самая близкая вещь, которую вы можете получить для INSERT DELAYED. Все DML (INSERT, UPDATE и DELETE) будут кэшироваться в пуле буферов InnoDB. Транзакционная информация для записей немедленно записывается в журналы повторов (ib_logfile0, ib_logfile1). Записи, которые публикуются в пуле буферов, периодически сбрасываются из памяти на диск через ibdata1 (InsertBuffer для вторичных индексов, двойной буфер записи). Чем больше буферный пул, тем большее количество INSERT может быть кэшировано. В системе с 8 ГБ или более ОЗУ используйте 75-80% ОЗУ в качестве innodb_buffer_pool_size. В системе с очень небольшим объемом оперативной памяти - 25% (для размещения ОС).

CAVEAT: Вы можете установить innodb_doublewrite в 0, чтобы ускорить запись еще больше, но с риском целостности данных. Вы также можете ускорить процесс, установив innodb_flush_method в O_DIRECT, чтобы предотвратить кеширование InnoDB в ОС.

Восстановить журналы ( размер innodb_log_file_size )

По умолчанию журналы повторов имеют имена ib_logfile0 и ib_logfile1 и будут по 5 МБ каждый. Размер должен быть 25% от innodb_buffer_pool_size. Если журналы повторов уже существуют, добавьте новый параметр в my.cnf, завершите работу mysql, удалите их и перезапустите mysql .

Буфер журналов ( размер innodb_log_buffer_size )

В буфере журнала хранятся изменения в оперативной памяти перед их сбросом в журналы повторов. По умолчанию это 8M. Чем больше буфер журнала, тем меньше дисковый ввод-вывод. Будьте осторожны с очень большими транзакциями, так как это может замедлить COMMIT на миллисекунды.

Доступ к нескольким процессорам

MySQL 5.5 и плагин MySQL 5.1 InnoDB имеют настройки для доступа InnoDB Storage Engine к нескольким процессорам. Вот параметры, которые вам нужно установить:

  • innodb_thread_concurrency устанавливает верхнюю границу количества одновременных потоков, которые InnoDB может держать открытыми. Обычно рекомендуется установить для этого значение (2 X Количество процессоров) + Количество дисков. В прошлом году я воочию узнал из конференции Percona NYC Conference, что вы должны установить это значение на 0, чтобы предупредить InnoDB Storage Engine, чтобы найти лучшее число потоков для среды, в которой он работает.
  • innodb_concurrency_tickets устанавливает количество потоков, которые могут безнаказанно обходить проверку параллелизма. После того, как этот предел достигнут, проверка параллельности потока снова становится нормой.
  • innodb_commit_concurrency устанавливает количество одновременных транзакций, которые могут быть зафиксированы. Поскольку значение по умолчанию равно 0, не устанавливая его, можно одновременно фиксировать любое количество транзакций.
  • innodb_thread_sleep_delay устанавливает количество миллисекунд, в течение которых поток InnoDB может бездействовать до повторного входа в очередь InnoDB. По умолчанию 10000 (10 секунд).
  • innodb_read_io_threads (установите это в 3000) и innodb_write_io_threads (установите это в 7000) (оба начиная с MySQL 5.1.38) выделяют указанное количество потоков для чтения и записи. По умолчанию установлено значение 4, а максимальное значение равно 64. Установите для них значение 64. Кроме того, установите для innodb_io_capacity значение 10000.

Обновление до MySQL 5.5

Если у вас MySQL 5.0, обновитесь до MySQL 5.5. Если у вас MySQL 5.1.37 или более ранней версии, обновитесь до MySQL 5.5. Если у вас MySQL 5.1.38 или выше и вы хотите остаться в MySQL 5.1, установите плагин InnoDB. Таким образом, вы можете воспользоваться всеми процессорами для InnoDB.

RolandoMySQLDBA
источник
память моего сервера составляет 2 ГБ, поэтому в соответствии с памятью я установил пул буферов innodb на 500 МБ, а файлы журналов - на 25% для пула, а также установил буфер журнала на 64 МБ Но все же сервер сильно занят. Должен ли я обновить память? Кроме того, мой сервер находится на 32-битной Ubuntu, так что я могу установить максимум 4 ГБ памяти.
Шашанк
Если сервер предназначен только для MySQL (без apache, без PHP), то innodb_buffer_pool_size может занимать 75% от 2 ГБ, что составляет 1536 МБ. Если вы обновите до 4 ГБ, innodb_buffer_pool_size может быть 3G. Файлы журналов должны составлять 25% от пула буферов, как вы указали.
RolandoMySQLDBA
Сервер работает под управлением apache2, mysql и php. Следует ли мне обновить память в этой ситуации или есть какое-либо оптимальное решение, кроме пула буферов innodb?
Шашанк
Этот парень не согласен с вами: percona.com/blog/2008/11/21/… С Percona трудно спорить.
Zenexer
Роландо - предлагаю добавить в ответ обновления с 5.6 и 5.7. Значения по умолчанию изменились; другие настройки доступны; и т.д. Может включать в себя Percona и MariaDB и 8.0 советов.
Рик Джеймс
2

INT (2) по-прежнему использует 4 байта - возможно, вы имели в виду TINYINT UNSIGNED?

Сколько разных значений в сетно? Если он маленький, ключ (setno) никогда не будет использоваться. INSERTing должен обновить этот индекс; удаление КЛЮЧА ускорит вставку некоторых.

CHAR (10) - это flagвсегда 10 символов? А в utf8? Возможно, вы могли бы использовать флаг VARCHAR (10) CHARACTER SET ascii

Пакетные вставки - 100 за раз будет работать в 10 раз быстрее. (За 100 входит в «убывающую отдачу».)

Какова ценность автокоммитов? Вы упаковываете каждую вставку в BEGIN ... COMMIT? Какое значение имеет innodb_flush_log_at_trx_commit?

Рик Джеймс
источник
как получить вставку в пакете, если данные вставляются через внешний источник, например, из разных клиентов с разными значениями ... это надежно, если я использовал: codeвставка в значения t_name (col1, col2, col3) (val1, val2, val3), (val1, val2, val3), (val1, val2, val3), (val1, val2, val3), (val1, val2, val3); code
Шашанк
1

Настройте очередь. Приложение будет записывать в очередь по 1 строке за раз, а затем извлекать строки и вставлять их в базу данных в пакетном режиме на основе количества строк или количества времени, прошедшего с момента последней вставки.

Я видел, что пакетирование 10 000 вставок за раз является самым быстрым, поэтому вам нужно проверить, чтобы найти подходящее место.

Вы можете создать свою собственную простую систему очередей или использовать существующую. Вот несколько примеров: HornetQ и File :: Queue . Вот сообщение о SE, в котором перечислены некоторые другие полезные опции: очереди сообщений в perl, php, python .

dabest1
источник
Я согласен с этим подходом - я пакетирую ~ 1500 вставок каждые 5 секунд в одном приложении, и это менее секунды. В mysql, похоже, реализован какой-то внутренний механизм, благодаря которому пакетная вставка происходит очень быстро.
Дон Вул