Самый эффективный способ поиска в SQL? - PullRequest
8 голосов
/ 06 марта 2012

У меня есть база данных с 75 000+ строк с добавлением 500+ записей в день.

У каждой строки есть заголовок и описание.

Я создал RSS-ленту, которая дает вам последние записидля конкретного поискового запроса (например, http://site.com/rss.rss?q=Pizza будет выводить RSS для поискового запроса «Пицца»).

Мне было интересно, как лучше написать SQL-запрос для этого.Сейчас у меня есть:

SELECT * 
FROM 'table' 
WHERE (('title' LIKE %searcherm%) OR ('description' LIKE %searcherm%))
LIMIT 20;

Но проблема в том, что для выполнения запроса требуется от 2 до 10 секунд.

Есть ли лучший способ написать запрос, нужно ли мнекэшировать результаты (и как мне это сделать?) или что-то изменить структуру базы данных ускорит запрос (индексы?)

Ответы [ 7 ]

9 голосов
/ 06 марта 2012

Относительно простым решением для этого будет включение индекса FULLTEXT в эти два поля и последующий поиск с использованием этого индекса.

ALTER TABLE table ADD FULLTEXT(title, description);

Тогда вам нужно будет выполнить поиск, и вы сделаете следующее:

SELECT id FROM table
WHERE MATCH (title, description) AGAINST ('keyterm');

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

Кроме того, полнотекстовый индекс имеет некоторый ограничивающий алгоритм для определения релевантности. Вы можете прочитать больше об этом здесь

EDIT

В операторе alter я пропустил полнотекстовое имя индекса, оно должно быть:

ALTER TABLE table ADD FULLTEXT ft_index_name(title, description);
4 голосов
/ 06 марта 2012

Попробуйте:

SELECT * FROM table
WHERE MATCH (title,description) AGAINST (searchterm);

Убедитесь, что вы добавили полный текстовый указатель на заголовок и описание вместе.

Не пытайтесь изобретать велосипед заново.MATCH и AGAINST * предоставлены mysql , чтобы сделать именно это и сделать вашу жизнь проще.Однако обратите внимание, что полнотекстовый поиск работает в таблицах MyISAM.Вы можете обойти и для InnoDb.Вы можете просто добавить индекс FT, изменив таблицу следующим образом:

ALTER TABLE table ADD FULLTEXT(title,description);
3 голосов
/ 06 марта 2012

Если вы используете запрос с LIKE '%term%', индексы использовать нельзя. Их можно использовать только в том случае, если вы используете запрос типа 'term%'. Подумайте об адресной книге с вкладками, вы можете найти очень быстрые контакты, начинающиеся с буквы L, но чтобы найти контакты с on где-то в слове, вам нужно отсканировать всю адресную книгу.

Лучшей альтернативой может быть использование полнотекстовых индексов:

CREATE FULLTEXT INDEX title_desc
ON table (title, description)

А потом в запросе:

SELECT title, description FROM table
WHERE MATCH (title, description) AGAINST ('+Pizza')
0 голосов
/ 06 марта 2012

Попробуйте выполнить один из следующих четырех запросов:

select * from myTable where concat_ws(' ',title,description) like '%pizza%';
select * from myTable where concat_ws(' ',title,description) regexp '.*pizza+.*';
select title,description from myTable where concat_ws(' ',title,description) like '%pizza%';
select title,description from myTable where concat_ws(' ',title,description) regexp '.*pizza+.*';

смысл использовать concat перед поиском

0 голосов
/ 06 марта 2012

Я бы согласился с ответом JohnB или gtr32x (полнотекстовое индексирование).Чтобы дополнить их ответ, есть ручной способ создания простого полнотекстового индекса, который прост и очень быстр ...

Разделите заголовок и описание на ключевые слова и поместите их в таблицу Keywords, которая имеетвнешний ключ к оригинальной статье RSS.Убедитесь, что столбец ключевых слов в Keywords проиндексирован.Вы можете сделать что-то вроде:

SELECT DISTINCT ra.* 
FROM RssArticle ra
INNER JOIN Keywords k ON k.ArticleID = ra.ArticleID
   WHERE k IN ( 'SearchTerm1', 'SearchTerm2', 'SearchTerm3')
LIMIT 20;

И это быстро!

0 голосов
/ 06 марта 2012
  1. Вы создали индекс для title и для description?
  2. Вы должны рассмотреть Sphinx для возможностей полнотекстового поиска.

Спасибо за комментарий Тайлер.

Я повторяю свой ответ:

1) Создайте индекс для столбцов title и description, но ваш запрос будет ограничен приведенным ниже примером, и это не идеально для поиска всех соответствующих строк:

SELECT * 
FROM 'table' 
WHERE title LIKE 'searcherm%' OR description LIKE 'searcherm%'
LIMIT 20;

2) Как уже упоминалось, используйте Полнотекстовый поиск MySQL , но вы ограничены механизмом таблиц MyISAM, так как он недоступен для InnoDB. Тем не менее, вы можете смешивать движки в MySQL, так что вы можете сделать эту таблицу MyISAM, даже если все ваши другие таблицы InnoDB.

3) Использовать внешнюю систему полнотекстового поиска, например Sphinx . Это даст вам более релевантные результаты поиска (полнотекстовый поиск MySQL оставляет желать лучшего), он будет работать лучше и отвлечет бремя полнотекстового поиска от вашей базы данных.

0 голосов
/ 06 марта 2012

Несколько указателей: опустите * в своем операторе выбора и извлеките только искомые критерии и обязательно добавьте индексы к столбцам, по которым производится поиск.

SELECT `title`,`description` 
FROM `table` 
WHERE `title` LIKE '%$searchterm%' OR `description` LIKE '%$searchterm%' LIMIT 25;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...