У меня огромный стол, какОптимизация большой таблицы ключевых слов?
CREATE TABLE IF NOT EXISTS `object_search` (
`keyword` varchar(40) COLLATE latin1_german1_ci NOT NULL,
`object_id` int(10) unsigned NOT NULL,
PRIMARY KEY (`keyword`,`media_id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 COLLATE=latin1_german1_ci;
с около 39 миллионов строк (используя более ГБ пространства 1), содержащий данные, индексированные на 1 млн записей в таблице объектов (где object_id
точек, в).
Теперь поиск через это с запросом, как
SELECT object_id, COUNT(object_id) AS hits
FROM object_search
WHERE keyword = 'woman' OR keyword = 'house'
GROUP BY object_id
HAVING hits = 2
уже значительно быстрее, чем делать LIKE
поиск на наборной keywords
поле в object
таблице, но по-прежнему занимает до 1 минуты.
Это объясняет как выглядит:
+----+-------------+--------+------+---------------+---------+---------+-------+--------+----------+--------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+--------+------+---------------+---------+---------+-------+--------+----------+--------------------------+
| 1 | SIMPLE | search | ref | PRIMARY | PRIMARY | 42 | const | 345180 | 100.00 | Using where; Using index |
+----+-------------+--------+------+---------------+---------+---------+-------+--------+----------+--------------------------+
Полный объяснить с присоединился object
и object_color
и object_locale
таблицы, в то время как выше запрос выполняется в подзапрос, чтобы избежать накладных расходов, выглядит следующим образом:
+----+-------------+-------------------+--------+---------------+-----------+---------+------------------+--------+----------+---------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------------------+--------+---------------+-----------+---------+------------------+--------+----------+---------------------------------+
| 1 | PRIMARY | <derived2> | ALL | NULL | NULL | NULL | NULL | 182544 | 100.00 | Using temporary; Using filesort |
| 1 | PRIMARY | object_color | eq_ref | object_id | object_id | 4 | search.object_id | 1 | 100.00 | |
| 1 | PRIMARY | locale | eq_ref | object_id | object_id | 4 | search.object_id | 1 | 100.00 | |
| 1 | PRIMARY | object | eq_ref | PRIMARY | PRIMARY | 4 | search.object_id | 1 | 100.00 | |
| 2 | DERIVED | search | ref | PRIMARY | PRIMARY | 42 | | 345180 | 100.00 | Using where; Using index |
+----+-------------+-------------------+--------+---------------+-----------+---------+------------------+--------+----------+---------------------------------+
Моя главная цель - просканировать это через 1 или 2 секунды.
Итак, существуют ли дальнейшие методы улучшения скорости поиска по ключевым словам?
Update 2013-08-06:
Применение наиболее внушения Невилл K «s теперь у меня есть следующие настройки:
CREATE TABLE `object_search_keyword` (
`keyword_id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`keyword` varchar(64) COLLATE latin1_german1_ci NOT NULL,
PRIMARY KEY (`keyword_id`),
FULLTEXT KEY `keyword_ft` (`keyword`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 COLLATE=latin1_german1_ci;
CREATE TABLE `object_search` (
`keyword_id` int(10) unsigned NOT NULL,
`object_id` int(10) unsigned NOT NULL,
PRIMARY KEY (`keyword_id`,`media_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
новый запрос объясним выглядит следующим образом :
+----+-------------+----------------+----------+--------------------+------------+---------+---------------------------+---------+----------+----------------------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+----------------+----------+--------------------+------------+---------+---------------------------+---------+----------+----------------------------------------------+
| 1 | PRIMARY | <derived2> | ALL | NULL | NULL | NULL | NULL | 24381 | 100.00 | Using temporary; Using filesort |
| 1 | PRIMARY | object_color | eq_ref | object_id | object_id | 4 | object_search.object_id | 1 | 100.00 | |
| 1 | PRIMARY | object | eq_ref | PRIMARY | PRIMARY | 4 | object_search.object_id | 1 | 100.00 | |
| 1 | PRIMARY | locale | eq_ref | object_id | object_id | 4 | object_search.object_id | 1 | 100.00 | |
| 2 | DERIVED | <derived4> | system | NULL | NULL | NULL | NULL | 1 | 100.00 | |
| 2 | DERIVED | <derived3> | ALL | NULL | NULL | NULL | NULL | 24381 | 100.00 | |
| 4 | DERIVED | NULL | NULL | NULL | NULL | NULL | NULL | NULL | NULL | No tables used |
| 3 | DERIVED | object_keyword | fulltext | PRIMARY,keyword_ft | keyword_ft | 0 | | 1 | 100.00 | Using where; Using temporary; Using filesort |
| 3 | DERIVED | object_search | ref | PRIMARY | PRIMARY | 4 | object_keyword.keyword_id | 2190225 | 100.00 | Using index |
+----+-------------+----------------+----------+--------------------+------------+---------+---------------------------+---------+----------+----------------------------------------------+
Многие из них получают Едут от ключевого слова по сравнению подзапрос быть вложены в другой подзапрос, который не делает ничего, кроме подсчитать количество строк, возвращаемых:
SELECT SQL_NO_CACHE object.object_id, ..., @rn AS numrows
FROM (
SELECT *, @rn := @rn + 1
FROM (
SELECT SQL_NO_CACHE search.object_id, COUNT(turbo.object_id) AS hits
FROM object_keyword AS kwd
INNER JOIN object_search AS search ON (kwd.keyword_id = search.keyword_id)
WHERE MATCH (kwd.keyword) AGAINST ('+(woman) +(house)')
GROUP BY search.object_id HAVING hits = 2
) AS numrowswrapper
CROSS JOIN (SELECT @rn := 0) CONST
) AS turbo
INNER JOIN object AS object ON (search.object_id = object.object_id)
LEFT JOIN object_color AS object_color ON (search.object_id = object_color.object_id)
LEFT JOIN object_locale AS locale ON (search.object_id = locale.object_id)
ORDER BY timestamp_upload DESC
Этот запрос фактически будет работать в течение ~ 6 секунд, так как он ищет двух ключевых слов. Чем больше ключевых слов я ищу, тем быстрее выполняется поиск.
Любой способ дальнейшей оптимизации?
Обновление 2013-08-07
Блокирующий вещь кажется почти наверняка быть приложены ORDER BY
заявление. Без него запрос выполняется менее чем за секунду.
Итак, есть ли способ быстрее отсортировать результат? Любые предложения приветствуются, даже хакерские, которые потребуют последующей обработки в другом месте.
Обновление 2013-08-07 позже в тот же день
Alright дамы и господа, гнездящихся заявления WHERE
и ORDER BY
в другом слое подзапроса, чтобы не позволить ей возиться с таблицами не нужно примерно в два раза его производительность снова:
SELECT wowrapper.*, locale.title
FROM (
SELECT SQL_NO_CACHE object.object_id, ..., @rn AS numrows
FROM (
SELECT *, @rn := @rn + 1
FROM (
SELECT SQL_NO_CACHE search.media_id, COUNT(search.media_id) AS hits
FROM object_keyword AS kwd
INNER JOIN object_search AS search ON (kwd.keyword_id = search.keyword_id)
WHERE MATCH (kwd.keyword) AGAINST ('+(frau)')
GROUP BY search.media_id HAVING hits = 1
) AS numrowswrapper
CROSS JOIN (SELECT @rn := 0) CONST
) AS search
INNER JOIN object AS object ON (search.object_id = object.object_id)
LEFT JOIN object_color AS color ON (search.object_id = color.object_id)
WHERE 1
ORDER BY object.object_id DESC
) AS wowrapper
LEFT JOIN object_locale AS locale ON (jfwrapper.object_id = locale.object_id)
LIMIT 0,48
Поисковые запросы, которые имели 12 секунд (одного ключевого слова, ~ результаты 200K) в настоящее время принимают 6 и поиск двух ключевых слов, которые потребовалось 6 секунд (60 тысяч результатов) в настоящее время занимает около 3,5 С.Е. CS.
Теперь это уже значительное улучшение, но есть ли шанс направить это дальше?
Обновление 2013-08-08 рано день
расстегнул, что последний вариант вложенной запросы, так как он на самом деле замедлил другие вариации этого ... я сейчас пытаюсь каким-то другое вещи с разными таблицами таблиц и FULLTEXT
индексы с использованием MyISAM для выделенной таблицы поиска с комбинированным полем ключевых слов (запятая разделена в поле TEXT
).
Обновление 2013-08-08
Хорошо, простой индекс полнотекстового реально не поможет.
Назад к предыдущей настройке, единственной блокировкой является ORDER BY
(которая использует временную таблицу и файловый центр). Без него поиск завершен менее чем за секунду!
Так в основном то, что осталось от всего этого:
Как оптимизировать ORDER BY
заявление работать быстрее, вероятно, за счет исключения использования временной таблицы?
Можете ли вы отправить результат «EXPLAIN» для запроса? – Vatev
@ Ватев там! –
Я только что запустил 'OPTIMIZE TABLE', и теперь это между 10 и 30 секундами. –