InnoDB вставляет очень медленно и медленно - PullRequest
10 голосов
/ 02 февраля 2012

Я недавно переключил свои таблицы проектов на InnoDB (думая, что отношения были бы хорошими, иметь). Я использую скрипт PHP для индексирования около 500 продуктов одновременно.

Таблица хранения слов / идентификаторов:

    CREATE TABLE `windex` (
 `word` varchar(64) NOT NULL,
 `wid` int(10) unsigned NOT NULL AUTO_INCREMENT,
 `count` int(11) unsigned NOT NULL DEFAULT '1',
 PRIMARY KEY (`wid`),
 UNIQUE KEY `word` (`word`)
) ENGINE=InnoDB AUTO_INCREMENT=324551 DEFAULT CHARSET=latin1

В другой таблице хранятся ассоциации идентификатора продукта / идентификатора слова:

CREATE TABLE `indx_0` (
 `wid` int(7) unsigned NOT NULL,
 `pid` int(7) unsigned NOT NULL,
 UNIQUE KEY `wid` (`wid`,`pid`),
 KEY `pid` (`pid`),
 CONSTRAINT `indx_0_ibfk_1` FOREIGN KEY (`wid`) REFERENCES `windex` (`wid`) ON DELETE CASCADE ON UPDATE CASCADE,
 CONSTRAINT `indx_0_ibfk_2` FOREIGN KEY (`pid`) REFERENCES `product` (`ID`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=latin1

Скрипт был протестирован с использованием MyISAM и индексирует продукты относительно быстро (намного, намного быстрее, чем InnoDB). В первый раз, когда я работал в InnoDB, это было смехотворно медленно, но после того, как я вложил больше значений, я в итоге сильно (но не достаточно) ускорил его.

Я бы предположил, что innodb будет намного быстрее для такого типа вещей из-за блокировок на уровне строк, но это не так.

Я создаю запрос, который выглядит примерно так:

SELECT
title,keywords,upc,...
FROM product
WHERE indexed = 0
LIMIT 500

Я создаю цикл и заполняю массив всеми словами, которые необходимо добавить в windex, и всеми парами id / id продукта, которые необходимо добавить в indx_0.

Поскольку innodb продолжает увеличивать мои значения автоинкремента всякий раз, когда я делаю «REPLACE INTO» или «INSERT IGNORE INTO», который завершается ошибкой из-за дублирования значений, я должен убедиться, что добавленные мной значения еще не существуют. Для этого я сначала выбираю все значения, которые существуют, используя такой запрос:

SELECT wid,word
FROM windex
WHERE
word = "someword1" or word = "someword2" or word = "someword3" ... ...

Затем я отфильтровываю свой массив по существующим результатам, поэтому все новые слова, которые я добавляю, на 100% новые.

Это занимает около 20% общего времени выполнения. Остальные 80% идут на добавление парных значений в indx_0, для которого есть еще много значений.

Вот пример того, что я получаю.

0,4806 секунд, чтобы выбрать продукты. (Всего 0,4807 с).
0.0319 секунд, чтобы собрать 500 предметов. (Всего 0,5126 с).
5,2396 секунд, чтобы выбрать значения Windex для сравнения. (Всего 5,7836 с).
1.8986 секунд для обновления счетчика. (Всего 7,6822 с).
0,0641 секунды, чтобы добавить 832 записи Windex. (Всего 7,7464 с).
17,2725 секунд, чтобы добавить индекс 3435 пар pid / wid. (Всего 25,7752 с).
Операция заняла 26,07 секунды для индексации 500 продуктов.

Все 3435 пар выполняются в одном запросе, например:

INSERT INTO indx_0(pid,wid)
VALUES (1,4),(3,9),(9,2)... ... ...

Почему InnoDB намного медленнее, чем MyISAM в моем случае?

Ответы [ 2 ]

18 голосов
/ 02 февраля 2012

InnoDB обеспечивает более сложную структуру ключей, чем MyIsam (FOREIGN KEYS), и в InnoDB процесс восстановления ключей очень медленный.Вы должны заключить все операторы обновления / вставки в одну транзакцию (это на самом деле довольно быстро в InnoDB, как только у меня было около 300 000 запросов на вставку в таблицу InnoDb с 2 индексами, и это заняло около 30 минут, после того как я вложил каждые 10 000 вставок в BEGIN TRANSACTION и COMMIT это заняло менее 2 минут).

Я рекомендую использовать:

BEGIN TRANSACTION;
SELECT ... FROM products;
UPDATE ...;
INSERT INTO ...;
INSERT INTO ...;
INSERT INTO ...;
COMMIT;

Это заставит InnoDB обновлять индексы только один раз, а не несколько сотен раз.

Дайте мне знать, если это сработало

6 голосов
/ 11 августа 2015

У меня была похожая проблема, и кажется, что в InnoDB по умолчанию включен innodb_flush_log_at_trx_commit, который сбрасывает каждый запрос вставки / обновления в вашем файле журнала жесткого диска. Скорость записи вашего жесткого диска является узким местом для этого процесса.

Так что попробуйте изменить ваш конфигурационный файл mysql

  `innodb_flush_log_at_trx_commit  = 0`

Перезапустите службу MySQL.

Я столкнулся с ускорением x100 на вставках.

...