Как ускорить LIKE

miha25
Дата: 10.02.2013 03:09:42
Есть таблица

CREATE TABLE IF NOT EXISTS `jb_board` (
  `id` int(7) NOT NULL auto_increment,
  `id_category` smallint(3) NOT NULL,
  `user_id` int(6) NOT NULL default '0',
  `type` enum('s','p','u','o','a','v','r','m') default 'p',
  `autor` varchar(255) NOT NULL,
  `title` varchar(255) NOT NULL,
  `email` varchar(30) NOT NULL,
  `subscribe` enum('yes','no') character set cp1251 NOT NULL default 'yes',
  `city` varchar(50) NOT NULL,
  `city_id` smallint(6) NOT NULL,
  `url` varchar(255) NOT NULL,
  `click` smallint(6) NOT NULL default '0',
  `contacts` text NOT NULL,
  `text` text NOT NULL,
  `price` int(11) NOT NULL default '1',
  `price_val` text NOT NULL,
  `video` varchar(128) NOT NULL,
  `hits` int(11) NOT NULL default '0',
  `old_mess` enum('new','old') NOT NULL default 'new',
  `checked` enum('yes','no','edit','del') NOT NULL default 'no',
  `checkbox_top` smallint(1) NOT NULL default '0',
  `top_time` datetime NOT NULL default '0000-00-00 00:00:00',
  `send_notice_vip_sms` smallint(1) NOT NULL default '0',
  `checkbox_select` smallint(1) NOT NULL default '0',
  `select_time` datetime NOT NULL default '0000-00-00 00:00:00',
  `send_notice_select_sms` smallint(1) NOT NULL default '0',
  `tags` varchar(255) NOT NULL,
  `send_notice_day` smallint(1) NOT NULL default '0',
  `time_delete` smallint(6) NOT NULL default '30',
  `date_add` datetime NOT NULL,
  `ip` text NOT NULL,
  `gmaps` varchar(255) NOT NULL,
  `cat_fields` text NOT NULL,
  PRIMARY KEY  (`id`),
  KEY `id_category` (`id_category`,`type`,`city_id`,`old_mess`),
  KEY `checkbox_top` (`checkbox_top`,`checkbox_select`),
  KEY `top_time` (`top_time`),
  KEY `date_add` (`date_add`),
  KEY `autor` (`autor`),
  KEY `title` (`title`),
  KEY `user_id` (`user_id`),
  KEY `tags` (`tags`)
) ENGINE=MyISAM  DEFAULT CHARSET=utf8 PACK_KEYS=0 CHECKSUM=1 AUTO_INCREMENT=706608 ;


с поля tags нужно выбрать записи где есть слово например: город

поле tags состоит из пяти слов, пример: слово, слово, город, слово, слово

делаю так

SELECT jb_board.id AS board_id, DATE_FORMAT(jb_board.date_add,'%d.%m.%Y') AS dateAdd,
  jb_board.id_category, jb_board.title, jb_board.text, jb_board.price, jb_board.price_val, jb_board.city, jb_board.checkbox_select
FROM jb_board
WHERE old_mess = 'old' AND jb_board.tags LIKE '%".город."%' ".$GLOBALS['subQuery']."
ORDER by jb_board.checkbox_select DESC, date_add DESC
LIMIT 0, 20

но такая выборка работает очень долго, пробовал так

SELECT jb_board.id AS board_id, DATE_FORMAT(jb_board.date_add,'%d.%m.%Y') AS dateAdd,
  jb_board.id_category, jb_board.title, jb_board.text, jb_board.price, jb_board.price_val, jb_board.city, jb_board.checkbox_select
FROM jb_board
WHERE old_mess = 'old' AND jb_board.tags LIKE '".город."%' ".$GLOBALS['subQuery']."
ORDER by jb_board.checkbox_select DESC, date_add DESC
LIMIT 0, 20

но так находит не все записи, как можно ускорить и при этом не терять кол-во?
vkle
Дата: 10.02.2013 03:21:21
miha25
поле tags состоит из пяти слов
Раз уж к-во слов фиксировано, не рассматривали вариант разбить это поле на несколько отдельных полей?

По большому же счету, нужно переделывать архитектуру. Сделать таблицу-справочник тегов и таблицу связей.
miha25
Дата: 10.02.2013 03:24:33
vkle, а как мне теперь с этой таблицы вытянуть поле tags в другую таблицу и как надо переписать запрос?
javajdbc
Дата: 10.02.2013 03:25:26
miha25,

Вроде 100% для этого продумали FULLTEXT:

http://dev.mysql.com/doc/refman/5.0/en/fulltext-search.html
miha25
Дата: 10.02.2013 03:28:43
javajdbc, пожалуйста расшифруйте, я перешел по ссылке но для меня это темный лес, как это можно применить к моему запросу?
miha25
Дата: 10.02.2013 03:35:30
javajdbc, пробую переводить на русский все равно не пойму, как применить в моем случае, двое суток уже сижу над этим вопросом, пожалуйста если вам не сложно помогите, или подскажите в каком направлении мне копать
javajdbc
Дата: 10.02.2013 03:57:27
miha25,

https://www.google.ca/search?q=mysql+%D0%BF%D0%BE%D0%BB%D0%BD%D0%BE%D1%82%D0%B5%D0%BA%D1%81%D1%82%D0%BE%D0%B2%D1%8B%D0%B9+%D0%BF%D0%BE%D0%B8%D1%81%D0%BA&ie=utf-8&oe=utf-8&aq=t&rls=org.mozilla:en-US:official&client=firefox-a

например, первая ссылка
http://habrahabr.ru/post/40218/

вкратце -- надо сделать ФУЛТЕХТ индекс и использовать
МАТЧ-АГАИНСТ вместо ЛИКЕ.

Подробности как это сделать лечко читаются из ссылок.
javajdbc
Дата: 10.02.2013 04:01:49
....кроме того, у вас достаточно сложный запрос
и может быть медленым по разным причинам.

для дальнейшего обсуждения, полезно:
1. отформатировать запрос
2. поставьте слово EXPLAIN перед запросом и выдайте сюда результат.
3. сообшайте наблюдаемую скорость запроса (без ЕХПЛЕЙНа) и какую скорость хотите.
miha25
Дата: 10.02.2013 04:11:07
javajdbc, как раз читал http://habrahabr.ru/post/40218/,

делаю так

ALTER TABLE `jb_board` ADD FULLTEXT KEY `tags` (`tags`)

делаю выборку вот так

SELECT jb_board.id AS board_id, DATE_FORMAT(jb_board.date_add,'%d.%m.%Y') AS dateAdd, jb_board.id_category, jb_board.title, jb_board.text, jb_board.price, jb_board.price_val, jb_board.city, jb_board.checkbox_select FROM jb_board WHERE old_mess = 'old' AND MATCH (text) AGAINST ('ремонт') ".$GLOBALS['subQuery']." ORDER by jb_board.checkbox_select DESC, date_add DESC LIMIT ".$start.", ".$c['count_adv_on_index']

показывает

Warning: mysql_result(): supplied argument is not a valid MySQL result resource in /var/www/miha25/data/www/site.ru/inc/tags.inc.php on line 30
miha25
Дата: 10.02.2013 04:19:48
miha25, исправил ошибку

вместо:

SELECT jb_board.id AS board_id, DATE_FORMAT(jb_board.date_add,'%d.%m.%Y') AS dateAdd, jb_board.id_category, jb_board.title, jb_board.text, jb_board.price, jb_board.price_val, jb_board.city, jb_board.checkbox_select FROM jb_board WHERE old_mess = 'old' AND MATCH (text) AGAINST ('ремонт') ".$GLOBALS['subQuery']." ORDER by jb_board.checkbox_select DESC, date_add DESC LIMIT 0,20

надо было

SELECT jb_board.id AS board_id, DATE_FORMAT(jb_board.date_add,'%d.%m.%Y') AS dateAdd, jb_board.id_category, jb_board.title, jb_board.text, jb_board.price, jb_board.price_val, jb_board.city, jb_board.checkbox_select FROM jb_board WHERE old_mess = 'old' AND MATCH (tags) AGAINST ('ремонт') ".$GLOBALS['subQuery']." ORDER by jb_board.checkbox_select DESC, date_add DESC LIMIT 0,20

теперь реально быстрее работает