Я недавно переключил свои таблицы проектов на 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 в моем случае?