Гость
Целевая тема:
Создать новую тему:
Автор:
Форумы / MySQL [игнор отключен] [закрыт для гостей] / максимально оптимизировать запрос / 5 сообщений из 5, страница 1 из 1
09.03.2015, 05:42:20
    #38898646
scion4581
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
максимально оптимизировать запрос
Всем доброе время суток. В связи с оптимизацией запроса прошу помощи.

И так, есть основные сущности orders и filters.
[SRC sql]
CREATE TABLE IF NOT EXISTS `orders` (
`id` int(10) unsigned NOT NULL,
`made_year` year(4) NOT NULL COMMENT 'год производства',
`car_model_id` int(10) unsigned NOT NULL COMMENT 'модель',
`cabin_id` int(10) unsigned NOT NULL COMMENT 'тип кузова',
`drive_id` int(10) unsigned NOT NULL COMMENT 'тип привода',
`service_article_id` int(10) unsigned NOT NULL COMMENT 'группа услуги',
`spare_type` enum('any','original','unoriginal') DEFAULT NULL COMMENT 'тип запчасти',
`condition_type` enum('any','new','used') DEFAULT NULL COMMENT 'состояние запчасти'
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Инфо о машине в заказе' AUTO_INCREMENT=7 ;


CREATE TABLE IF NOT EXISTS `filters` (
`id` int(10) unsigned NOT NULL,
`name` varchar(255) NOT NULL COMMENT 'название фильтра',
`service_type_id` int(10) unsigned NOT NULL COMMENT 'категория',
`condition_type` enum('any','new','used') DEFAULT NULL COMMENT 'состояние запчасти',
`spare_type` enum('any','original','unoriginal') DEFAULT NULL COMMENT 'тип запчасти',
`user_id` int(10) unsigned NOT NULL COMMENT 'владелец фильтра',
`status` enum('active','inactive') NOT NULL DEFAULT 'active' COMMENT 'статус фильтра'
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='фильтры' AUTO_INCREMENT=2 ;

[/SRC]

Таблицы приведу не полностью а самые важные данные используемые в запросе.

Суть такова что одни пользователи составляют заказы, используя другие таблицы как например
car_models, cabin, drive - обыкновенные таблицы-справочники. А другие создают фильтры для получения
этих заказов. Но фильтр имеет множественный выбор, т.е. в один фильтр могут входит несколько моделей,
несколько годов производства, несколько групп запчастей. Поэтому есть таблицы реализующие множественный выбор,
типа filter_vs_model, filter_vs_made_year, filter_vs_article. Ниже примеры пары таких таблиц

Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
CREATE TABLE IF NOT EXISTS `filter_vs_model` (
`id` int(10) unsigned NOT NULL,
  `filter_id` int(10) unsigned NOT NULL COMMENT 'фильтер',
  `car_model_id` int(10) NOT NULL COMMENT 'модель'
) ENGINE=InnoDB  DEFAULT CHARSET=utf8 COMMENT='фильтры - модели' AUTO_INCREMENT=4 ;


CREATE TABLE IF NOT EXISTS `filter_vs_made_year` (
`id` int(10) unsigned NOT NULL,
  `filter_id` int(10) unsigned NOT NULL,
  `made_year` year(4) NOT NULL COMMENT 'года выпуска'
) ENGINE=InnoDB  DEFAULT CHARSET=utf8 COMMENT='фильтры - года производства' AUTO_INCREMENT=4 ;




И далее происходит выборка всех заказов совпадающих по фильтрам конкретных пользователей.
Собственно что я делаю. Сначала выбираю возможные совпадения нужных мне значений в заказе по фильтрам для
конкретного пользователя. Потом выбираю все заказы по определенным условиям, например есть заказы неактивные
или которые должны будут вскоре удалится и их не нужно выводить. Дальше объединяю эти выборки по нужным мне полям,
например по моделям, годам, группам услуг, и в финале результат я объединяю с таблицами-справочниками чтобы получить
"читабельные" значения из справочников а не айдишники.

Вот такой запрос получается:

Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
SELECT 

orders.id,
orders.name,
drive.name,
cabin.name,
article.name

FROM 
(SELECT DISTINCT
f_vs_model.car_model_id,
f_vs_year.made_year,
f_vs_article.service_article_id,
f.condition_type,
f.spare_type
                
FROM filters f    
    
JOIN filter_vs_model f_vs_model ON f_vs_model.filter_id = f.id
JOIN filter_vs_made_year f_vs_year ON f_vs_year.filter_id = f.id
JOIN filter_vs_article f_vs_article ON f_vs_article.filter_id = f.id

WHERE f.user_id = 'такой то' AND f.status = 'active' ) As filter

JOIN 

(SELECT 
 o.id,
 o.name,
 o.made_year,
 o.car_model_id,
 o.service_article_id,
 o.spare_type,
 o.condition_type,
 o.cabin_id,
 o.drive_id
 
FROM orders o
 
WHERE o.status = 'active' ) As orders ON 

filter.car_model_id = orders.car_model_id AND
filter.made_year = orders.made_year AND
filter.service_article_id = orders.service_article_id AND
filter.condition_type = orders.condition_type AND
filter.spare_type = orders.spare_type 

JOIN service_article article ON article.id = orders.service_article_id 
JOIN cabin ON cabin.id = orders.cabin_id 
JOIN drive ON drve.id = orders.drive_id 



привожу explain

Буду признателен если подскажите как можно еще оптимизировать запрос
...
Рейтинг: 0 / 0
10.03.2015, 02:26:48
    #38899303
javajdbc
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
максимально оптимизировать запрос
scion4581,


во-первых -- приведите ЕКСПЛЕЙН на КОНКРЕТНЫХ больших
данных, скопируйте продакшн базу а не изпользуйте
для отладки пустую базу.

второе -- еслли спрашиваете про скорость -- укажите как быстро
сейчас бежит и как быстро вы хотите чтоб бежало?

третье -- навскидку, в середине запроса у вас большой
селект по ОРДЕР с минимальным филтром по АКТИВ.
Последуюший ЖОИН остался без индексов.
(Скорее всего) имеет смысл раскрыть скобки и
джойнить напрямую с использованием индексов.
...
Рейтинг: 0 / 0
10.03.2015, 19:28:37
    #38900460
scion4581
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
максимально оптимизировать запрос
большое спасибо за ответ, но пока в разработке, поэтому данных мало очень.

По поводу второго join я думал будет быстрее если сначала выбрать те фильтры и заказы могут попасть в ответ, а не все.

Или может я бред говорю. Новичок просто.
...
Рейтинг: 0 / 0
11.03.2015, 08:07:21
    #38900664
Arhat109
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
максимально оптимизировать запрос
scion4581,

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

2. Надо помнить о том, что "подзапрос всегда теряет индексы"... соответственно баланс промежду сокращением объема данных из подзапроса и потеря производительности из-за потери индексов -- есть также "тонкая грань", зависящая ... от объемов данных. Отсюда, далеко не всегда вынесение части в подзапрос позволяет ускорить результат... надо точно знать чего творишь. Иногда разворачивание подзапроса в основной запрос как раз за счет применения индексов всё существенно ускоряет.

Ну вот, как-то так. Знающие спецы подправят ежели вчё. :)
...
Рейтинг: 0 / 0
11.03.2015, 08:10:12
    #38900668
Arhat109
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
максимально оптимизировать запрос
scion4581,

Да и ещё: при пользовании подзапросами надо помнить о том, что они по сути генерят временную табличку, и общая производительность будет сильно зависеть от количества данных в части select подзапроса. Иногда выгодно вытащить подзапросом только иденты требуемых данных, а из доп. поля добирать в главном запросе практически "повторно".
...
Рейтинг: 0 / 0
Форумы / MySQL [игнор отключен] [закрыт для гостей] / максимально оптимизировать запрос / 5 сообщений из 5, страница 1 из 1
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]