Serg86
14.12.2015 - 18:09
Всем доброго времени суток. Пытался решить проблему самостоятельно, но во всех источниках моя проблема упоминается вскользь, решил спросить у знатоков.
Версия MySQL: 5.6.26
Есть таблица с кучей полей (не принципиально), больше миллиона строк. Очень часто выполняются запросы поиска вида:
SELECT ........ WHERE cat in (630,359,611,534,541,535,538,531... бывает до 100 штук) AND region IN (126,127,6652.... бывает тож до 100 штук) ORDER by raised desc, date_add desc LIMIT 0, 30
Сразу добавлю что переформулировать запрос не получается, так как перечисляются дочерние категории и дочерние регионы региона и категории заданных в запросе.
Пытался прикрутить индексы, но как показал explain, в случае применения конструкции IN составной индекс не срабатывает, берется только первое значение, cat или region, в зависимости от того как составлен индекс.
Получается чтобы выбрать 30 строк приходится опрашивать как минимум несколько тысяч лишних, соответственно и запрос выполняется 10 - 15 сек.
Остюда вопрос: Предусмотрено ли в механизме использования составных индексов конструкция IN, и если да то как попробывать поэкспериментировать. Если нет, подскажите возможные решения проблемы.
sergeiss
14.12.2015 - 19:28
Цитата (Serg86 @ 14.12.2015 - 18:09) |
Пытался прикрутить индексы, но как показал explain, в случае применения конструкции IN составной индекс не срабатывает... |
Как именно был составлен этот индекс?
Цитата (Serg86 @ 14.12.2015 - 18:09) |
Есть таблица с кучей полей (не принципиально), больше миллиона строк. ... Сразу добавлю что переформулировать запрос не получается, так как перечисляются дочерние категории и дочерние регионы региона и категории заданных в запросе. |
По-моему, тут очень даже просятся партиции. Надо только правильно сделать дробление, чтобы оно работало максимально эффективно.
Цитата (Serg86 @ 14.12.2015 - 18:09) |
Если нет, подскажите возможные решения проблемы. |
Кроме партиций, возможно, тут получится сделать джойны? Для этого надо знать структуру таблицы.
Или, может быть, вообще как-то перестроить данные, разделить их на несколько таблиц? В любом случае показывай структуру своих данных, подумаем.
_____________
*
Хэлп по PHP*
Описалово по JavaScript *
Хэлп и СУБД для PostgreSQL*
Обучаю PHP, JS, вёрстке. Интерактивно и качественно. За разумные деньги. *
"накапливаю умение телепатии" (С) и "гуглю за ваш счет" (С)
Serg86
14.12.2015 - 19:45
Цитата |
Как именно был составлен этот индекс? |
Пробывал простой составной индекс с типом index из 2 полей cat region.
Цитата |
По-моему, тут очень даже просятся партиции. Надо только правильно сделать дробление, чтобы оно работало максимально эффективно. |
Как мне казалось в партициях нельзя чтобы записи одной партиции были разбросаны по талице.
Цитата |
Кроме партиций, возможно, тут получится сделать джойны? Для этого надо знать структуру таблицы. |
Можно пподробней.
sergeiss
14.12.2015 - 20:43
Цитата (Serg86 @ 14.12.2015 - 19:45) |
Можно поподробней. |
Ну так покажи структуру своих данных
Тогда можно будет подробнее что-то сказать.
_____________
*
Хэлп по PHP*
Описалово по JavaScript *
Хэлп и СУБД для PostgreSQL*
Обучаю PHP, JS, вёрстке. Интерактивно и качественно. За разумные деньги. *
"накапливаю умение телепатии" (С) и "гуглю за ваш счет" (С)
Serg86
15.12.2015 - 09:48
"NO_AUTO_VALUE_ON_ZERO";
SET time_zone = "+00:00";
/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
/*!40101 SET NAMES utf8mb4 */;
--
-- База данных: `sait`
--
-- --------------------------------------------------------
--
-- Структура таблицы `sait_db`
--
-- Создание: Дек 14 2015 г., 12:19
--
DROP TABLE IF EXISTS `sait_db`;
CREATE TABLE `sait_db` (
`id` int(11) NOT NULL,
`p` int(11) NOT NULL,
`ip` varchar(15) NOT NULL,
`uid` varchar(100) NOT NULL,
`cat` int(5) DEFAULT NULL,
`region` int(5) DEFAULT NULL,
`date_add` int(11) DEFAULT NULL,
`date_moder` int(11) NOT NULL,
`date_edit` int(11) DEFAULT NULL,
`date_del` int(11) DEFAULT NULL,
`user_id` int(11) DEFAULT NULL,
`status` int(1) DEFAULT '1',
`sendmail` int(1) NOT NULL,
`sort` int(10) DEFAULT '10000000',
`email` varchar(100) DEFAULT NULL,
`user` varchar(200) NOT NULL,
`title` varchar(300) DEFAULT NULL,
`text` text,
`marked` int(1) NOT NULL DEFAULT '0',
`raised` int(1) NOT NULL DEFAULT '0',
`block` int(1) NOT NULL DEFAULT '0',
`active` int(1) NOT NULL DEFAULT '0',
`counter` int(11) NOT NULL,
`moder_id` int(11) DEFAULT NULL,
`moder_edit` int(11) NOT NULL,
`moder_vozvrat_id` int(11) DEFAULT NULL,
`kol_vozv` int(11) DEFAULT NULL,
`prizn_vozv` text NOT NULL,
`rpubl` int(11) NOT NULL,
`nosend` int(10) UNSIGNED NOT NULL DEFAULT '0',
`subdomain` char(255) DEFAULT NULL,
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
--
-- Индексы сохранённых таблиц
--
--
-- Индексы таблицы `sait_db`
--
ALTER TABLE `sait_db`
ADD PRIMARY KEY (`id`),
ADD KEY `region` (`region`),
ADD KEY `cat` (`cat`),
ADD KEY `cat_region` (`cat`,`region`),
ADD KEY `status` (`status`),
ADD KEY `block_status` (`block`,`status`),
ADD KEY `userid_status` (`user_id`,`status`),
ADD KEY `p` (`p`);
--
-- AUTO_INCREMENT для сохранённых таблиц
--
--
-- AUTO_INCREMENT для таблицы `sait_db`
--
ALTER TABLE `sait_db`
MODIFY `id` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=243322;
/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
sergeiss
15.12.2015 - 16:11
Serg86, попробуй использовать в запросе FORCE INDEX(cat_region).
_____________
*
Хэлп по PHP*
Описалово по JavaScript *
Хэлп и СУБД для PostgreSQL*
Обучаю PHP, JS, вёрстке. Интерактивно и качественно. За разумные деньги. *
"накапливаю умение телепатии" (С) и "гуглю за ваш счет" (С)
Serg86
16.12.2015 - 09:08
Цитата |
Serg86, попробуй использовать в запросе FORCE INDEX(cat_region). |
Не прокатывает, только cat задействован.
Serg86
16.12.2015 - 09:09
Я еще подумывал както subdomain задействовать, чтоб он не по всей таблице cat перебирал, но здесь похожая проблема, субдоменов может быть нескольки и их опять в in писать придется.
S.Chushkin
16.12.2015 - 09:38
Цитата (Serg86 @ 14.12.2015 - 18:09) |
Получается чтобы выбрать 30 строк приходится опрашивать как минимум несколько тысяч лишних, соответственно и запрос выполняется 10 - 15 сек. |
Запрос не простой, поэтому "вполне может быть".
Выложите куда-нибудь дамп и пришлите мне ссылку на него (в личку). И сам запрос, полный, который Вам нужен.
Вечером сделаю оптимальный вариант запроса для mySQL. Более оптимальный вряд-ли у Вас получится без переделки структуры БД.
_____________
Рекламка / ad.pesow.com Хрень / mr-1.ru
Serg86
16.12.2015 - 14:46
Цитата |
Запрос не простой, поэтому "вполне может быть".
Выложите куда-нибудь дамп и пришлите мне ссылку на него (в личку). И сам запрос, полный, который Вам нужен. Вечером сделаю оптимальный вариант запроса для mySQL. Более оптимальный вряд-ли у Вас получится без переделки структуры БД.
|
Скинул в личку.
sergeiss
16.12.2015 - 16:00
Потом в теме напишите, как решили проблему. В том числе и сам запрос можно выложить.
_____________
*
Хэлп по PHP*
Описалово по JavaScript *
Хэлп и СУБД для PostgreSQL*
Обучаю PHP, JS, вёрстке. Интерактивно и качественно. За разумные деньги. *
"накапливаю умение телепатии" (С) и "гуглю за ваш счет" (С)
S.Chushkin
16.12.2015 - 17:45
ТС, Вы грозились:
1) больше миллиона строк
в дампе всего 50К
2) запрос выполняется 10 - 15 сек
у меня выполняется за 0.15с, из них 0.1 - ORDER BY
Уточните поточнее, что Вы хотите получить?
_____________
Рекламка / ad.pesow.com Хрень / mr-1.ru
Serg86
17.12.2015 - 10:21
Цитата |
больше миллиона строк в дампе всего 50К |
Да я всю таблицу не стал сливать просто, если надо солью больше
Цитата |
у меня выполняется за 0.15с, из них 0.1 - ORDER BY |
Будет миллион, будет больше, это логично.
Цитата |
Уточните поточнее, что Вы хотите получить?
|
Хотел по средствам индексов задействовать как можно меньше строк и соответственно уменьшить время запроса. Составныеиндексы не работают почемуто, судя по explain задействуется только cat. Вчера похимичил посидел, удалось задействовать status_cat, время значительно снизилось.
Задача на выходе получить 30 строк из таблицы, при этом максимально снизить количество затронутых строк.
Цитата |
из них 0.1 - ORDER BY |
Подскажите, можно с этим както бороться?
Serg86
17.12.2015 - 10:25
Еще заметил странную штуку, прикрутил новый индекс status_cat, погонял его немного, вроди время снизилось до адекватного, и я счастливый, на этом решил отложить проблему в долгий ящик. Через какоето время запускаю запрос снова и он выполняется за 15 секунд, тут же повторяю запрс и получаю 0,1 секунду, в чем прикол не пойму.
Serg86
17.12.2015 - 10:34
Цитата |
Уточните поточнее, что Вы хотите получить? |
Там если вы обратиливнимание есть еще субдомены, каждому субдомену в таблице регионов прикреплен ряд регионов, те что в запросе перечислены, вот я и думал, что может область поиска сразу по субдомену сузть, к примеру:
where subdomain = 'moskva' and status = 1 and (всё остальное) вот только тогда есть несколько прблем:
1) Не всегда область поиска целиком является субдоменом, а иногда идет пересечене, к примеру:
Ставропольский край (субдомен), минераловодский район (не субдмен, у него куча дочерних нас пунктов), Минеральные Воды (субдомен). Если искать в минераловодском райое, то придется учесть все его дочерние нас пункты плюс субдомен.
2) Иногда искать по нескольким субдоменам, если взять логику первого пункта по дереву регионов и поискать по ставропольскому краю, тогда ищем в двух субдоменах, снова получаем конструкцию IN и не факт что составные индексы будут работать.
Быстрый ответ:
Powered by dgreen
Здесь расположена полная версия этой страницы.