У меня есть следующий запрос... Он работает, но он работает очень медленно. Хотел ли кто-нибудь дать мне несколько советов по улучшению времени выполнения?
SELECT tb_clients.*, tb_clients_phone_fax.*
FROM tb_clients, tb_clients_phone_fax
WHERE tb_clients.client_id=tb_clients_phone_fax.client_id
AND MATCH (client_company,client_description,client_keywords) AGAINST ('test') > 0
AND CONCAT(client_address,' ',client_city,', ',client_state,' ',client_zip) LIKE '%brooklyn%'
LIMIT 10;
EDIT:
Вот информация о таблице:
CREATE TABLE `tb_clients` (
`client_id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`client_company` varchar(254) NOT NULL,
`client_address` varchar(254) NOT NULL,
`client_street` varchar(254) NOT NULL,
`client_city` varchar(254) NOT NULL,
`client_state` varchar(254) NOT NULL,
`client_zip` varchar(45) NOT NULL,
`client_email` varchar(254) NOT NULL,
`client_website` varchar(254) NOT NULL,
`client_description` text NOT NULL,
`client_keywords` text NOT NULL,
PRIMARY KEY (`client_id`) USING BTREE,
FULLTEXT KEY `client_company` (`client_company`,`client_description`,`client_keywords`)
) ENGINE=MyISAM AUTO_INCREMENT=68347 DEFAULT CHARSET=latin1;
и
CREATE TABLE `tb_clients_phone_fax` (
`client_phone_fax_id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`client_id` int(11) unsigned NOT NULL,
`client_phone_1` varchar(45) NOT NULL,
`client_phone_2` varchar(45) NOT NULL,
`client_phone_3` varchar(45) NOT NULL,
`client_fax_1` varchar(45) NOT NULL,
`client_fax_2` varchar(45) NOT NULL,
`client_fax_3` varchar(45) NOT NULL,
PRIMARY KEY (`client_phone_fax_id`) USING BTREE
) ENGINE=MyISAM AUTO_INCREMENT=33944 DEFAULT CHARSET=latin1 ROW_FORMAT=DYNAMIC;
tb_clients.client_id и tb_clients_phone_fax.client_id должны быть проиндексированы.
Но главной проблемой, по-видимому, являются сравнения двух строк, MATCH и LIKE с CONCAT. Вы уверены, что вокруг нет другой войны? например, избегая конкатенации всех полей адреса перед выполнением инструкции LIKE?
UPDATE: Похоже, что tb_clients_phone_fax.client_id не индексируется, это улучшит производительность, если она будет проиндексирована.
первый шаг при отладке медленных запросов работает EXPLAIN SELECT ...
и смотрит на то, что на самом деле делает MySQL, вместо того, чтобы гадать. Но да, похоже, что индекс tb_clients_phone_fax.client_id
поможет, как говорили другие.
Не зная о вашей ситуации, моя первая мысль, помимо упомянутого указателя, заключается в следующем: сколько строк находится в этих двух таблицах? Один из них - всего несколько тысяч, а другой - десять миллионов? Предполагая, что производительность вашего запроса не связана с соединением с очень большим набором данных, тогда:
Как говорили другие, проверьте, что ваши столбцы проиндексированы. Кроме того, почему не полный текст индексирует столбцы, которые вы конкатенации, а затем используйте второй запрос MATCH() AGAINST() в своем запросе вместо CONCAT() и LIKE?
Как насчет обновления кода для проверки, скажем, шаблона zip-кода, а затем для написания вашего запроса? Или, скажем, если это не шаблон в виде zip-кода, тогда не беспокойтесь о поиске этого столбца.
Одна вещь, которая хорошо работала для меня в ситуациях с большими объемами, где нужно искать всю (большую) таблицу, - это создать столбец, содержащий конкатенацию всей таблицы. Я помещаю полный текст в этот столбец и использую MATCH() AGAINST() и имеет очень быстрое время запроса, поэтому, по моему опыту, полнотекстовое индексирование выполняет свою работу.
Теперь, если у вас очень большая таблица, то объединение в режиме реального времени может стать неприемлемым. На данный момент у вас есть несколько вариантов, но все они - варианты выполнения этого объединения в фоновом режиме и сохранение этого результата в интересах конечных пользователей.
Не видя схемы таблицы, трудно сказать наверняка, но я бы предположил, что вы не ищете никаких указаний.
Попробуйте проверить руководство MySQL по полнотекстовым поискам: http://dev.mysql.com/doc/refman/5.0/en/fulltext-search.html Для лучшего ответа вам, скорее всего, потребуется опубликовать свою схему и указатели.
Вы должны начать, убедившись, что tb_clients
имеет индекс для client_id
, а tb_clients_phone_fax
имеет индекс на client_id
.
Затем попробуйте добавить индексы для клиентской компании, описания клиента, ключевых слов клиента.
Однако я готов поспорить, что основное замедление идет на сравнение, которое вы делаете на конкатенированном client_address,client_city,client_state,client_zip
, поэтому попробуйте найти другой способ сделать это сравнение без concat. Можете ли вы добавить поле в таблицу, в которой хранятся данные этих элементов, а затем просто сравнить это поле? (Ужасно я знаю)
Один очень маленький совет:
CONCAT(client_address,' ',client_city,', ',client_state,' ',client_zip) LIKE '%brooklyn%'
Нужен ли весь CONCAT? У вас много клиентов с brooklyn
внутри своего состояния или почтового индекса?
(Также вы понимаете, что это будет соответствовать адресу, например
1342 Бруклин-стрит
Foobar, MI 98765
Это намеренно?)
Я бы создал представление для таблицы tb_clients, у которой был "поддельный" столбец, который будет содержать вашу конкатенированную информацию.
Кроме того, я бы индексировал ранее упомянутые столбцы идентификаторов.
тогда вы должны использовать один и тот же базовый запрос, заменив представление для таблицы и опуская concat (поскольку это выполняется представлением как совокупный столбец)
Я в 5 минутах от работы, поэтому я не могу вдаваться в подробности. Если вам нужен код, пример sql и т.д., Дайте мне знать, и я поставлю что-то вместе для вас позже сегодня или завтра.