MySQL Select - улучшить спектакли
-
26-09-2019 - |
Вопрос
Я работаю в интернет-магазине, который продает продукты только по кредитам. Я показываю 10 продуктов на страницу в любой категории, каждый продукт имеет 3 различных ценника - 3 различных типа кредита. Все прошло довольно хорошо во время тестирования, время выполнения запросов было совершенным, но сегодня при перенесении изменений на производственный сервер, сайт «рухнул» примерно в 2 минутах. Запрос, который используется для выбора типов кредитов, иногда висит в течение ~ 10 секунд, и это часто бывает часто и, таким образом, не может идти в ногу и его Hella Slow. Отказ Таблица, которая используется для хранения данных, имеет примерно 2 записи MILOION, и каждый выбор выглядит следующим образом:
SELECT *
FROM products_loans
WHERE KOD IN("X17/Q30-10", "X17/12", "X17/5-24")
AND 369.27 BETWEEN CENA_OD AND CENA_DO;
3 Типы кредитов и цена, которая должна быть в пределах диапазона между Cena_OD и Cena_do, при этом возвращаются 3 ряда.
Но поскольку мне нужно отобразить 10 продуктов на странице, мне нужно запустить его через модифицированный выбор, используя ИЛИ, так как я не нашел никакого другого решения этого. Я спрашивал об этом здесь, но нет ответа. Как упоминалось в ссылке на пост, это должно быть сделано отдельно, так как есть нет Колонна, которая может быть использована в присоединении (кроме цена и кода конечно, но это закончилось очень очень плохо). Здесь show create table
, kod и cena_od / cena_do очень проиндексированы по индексу.
CREATE TABLE `products_loans` (
`KOEF_ID` bigint(20) NOT NULL,
`KOD` varchar(30) NOT NULL,
`AKONTACIA` int(11) NOT NULL,
`POCET_SPLATOK` int(11) NOT NULL,
`koeficient` decimal(10,2) NOT NULL default '0.00',
`CENA_OD` decimal(10,2) default NULL,
`CENA_DO` decimal(10,2) default NULL,
`PREDAJNA_CENA` decimal(10,2) default NULL,
`AKONTACIA_SUMA` decimal(10,2) default NULL,
`TYP_VYHODY` varchar(4) default NULL,
`stage` smallint(6) NOT NULL default '1',
PRIMARY KEY (`KOEF_ID`),
KEY `CENA_OD` (`CENA_OD`),
KEY `CENA_DO` (`CENA_DO`),
KEY `KOD` (`KOD`),
KEY `stage` (`stage`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
А также выбирая все типы кредитов, а позже фильтруют их кормушки PHP не работает хорошо, поскольку каждый тип имеет более 50 тысяч записей, и выбор также занимает слишком много времени ...
Любые идентификаторы о повышении скорости ценятся.
Редактировать:
Вот объяснение
+----+-------------+----------------+-------+---------------------+------+---------+------+--------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+----------------+-------+---------------------+------+---------+------+--------+-------------+
| 1 | SIMPLE | products_loans | range | CENA_OD,CENA_DO,KOD | KOD | 92 | NULL | 190158 | Using where |
+----+-------------+----------------+-------+---------------------+------+---------+------+--------+-------------+
Я попробовал комбинированный индекс, и он улучшил производительность на тестовом сервере от 0,44 ° до 0,06 сек, я не могу получить доступ к производственному серверу из дома, поэтому мне придется попробовать это завтра.
Решение
Попробуйте решить ваш запрос, как:
SELECT * FROM products_loans
WHERE KOD IN("X17/Q30-10", "X17/12", "X17/5-24")
AND CENA_OD >= 369.27
AND CENA_DO <= 369.27;
(MySQL не очень умный при выборе индексов) и проверьте производительность.
Следующая попытка - добавить комбинированный ключ - (ood, cena_od, cena_do)
А следующая крупная попытка - реформировать вашу базу, чтобы иметь продукты, разделенные от цен. Это должно действительно помочь.
PS: Вы также можете мигрировать в PostgreSQL, это умнее MySQL при выборе правильных индексов.
Другие советы
Ваша проблема заключается в том, что вы ищете интервалы, которые содержат точку (а не более нормальный запрос всех точек в интервале). Эти запросы не работают хорошо со стандартным индексом B-дерева, поэтому вместо этого вам нужно использовать индекс R-дерева. К сожалению MySQL не позволяет вам выбрать индекс R-дерева в столбце, но вы можете получить нужный индекс, изменив тип столбца в геометрию и используя геометрические функции для проверки, содержит ли интервал точка.
Видеть КвадраСтатья Список соседних против вложенных наборов: MySQL Где он объясняет это более подробно. Сейс использования отличается, но участвующие методики одинаковы. Вот экстракт из соответствующей части статьи:
Существует также определенный класс задач, которые требуют поиска всех диапазонов, содержащих известное значение:
- В поисках IP-адреса в списке башен IP-диапазона
- В поисках данной даты в пределах даты
и несколько других. Эти задачи могут быть улучшены с помощью возможностей R-деревьев MySQL.
MySQL может использовать только 1 ключ. Если вы всегда получаете запись на 3 столбцах, в зависимости от фактических данных (диапазон) в столбцах, одно из следующих, которые могут очень хорошо добавить серьезное количество производительности:
ALTER TABLE products_loans ADD INDEX(KOD, CENA_OD, CENA_DO);
ALTER TABLE products_loans ADD INDEX(CENA_OD, CENA_DO, KOD);
Обратите внимание, что порядок баллонов имеет значение! Если это не улучшает производительность, дайте нам EXPLAIN
вывод запроса.