2015-08-22 4 views
0

У меня есть две таблицы:заказ по запросу делает медленный

video (ID, TITLE, ..., UPLOADED_DATE) 
join_video_category (ID (not used), ID_VIDEO_ ID_CATEGORY) 

строки в видео: 4 500 000 | rows in join_video_category: 5 800 000

1 видео может иметь много категорий.

У меня есть запрос работает отлично, 20 мс максимум, чтобы получить результат:

SELECT * FROM video WHERE ID IN 
(SELECT ID_VIDEO FROM join_video_category WHERE ID_CATEGORY=11) 
LIMIT 1000; 

Этот запрос взять 1000 видео, порядок не важен.

НО, когда я хотел бы получить 10 последних видео из категории, мой запрос взять Arround 30-40 секунд:

SELECT * FROM video WHERE ID IN 
(SELECT ID_VIDEO FROM join_video_category WHERE ID_CATEGORY=11) 
ORDER BY UPLOADED_DATE DESC LIMIT 10; 

У меня есть индекс по ID_CATEGORY, ID_VIDEO, UPLOADED_DATE, в основном, на ID видео и join_video_category.

Я проверил его с помощью JOIN по моему запросу, это тот же результат.

ответ

1

Во-первых, сравнения относятся к двум очень различным запросам. Первый возвращает кучу видео всякий раз, когда он сталкивается с ними. Второй должен читать все видео, а затем отсортировать их.

Try переписывания это как JOIN:

SELECT v.* 
FROM video v JOIN 
    join_video_category vc 
    ON v.id = bc.id_video 
WHERE vc.ID_CATEGORY = 11 
ORDER BY v.UPLOADED_DATE DESC 
LIMIT 10; 

Это может или не может помочь. У вас много данных, поэтому у вас может быть много видео для данной категории. Если это так, то пункт where, который получает более свежие данные, может действительно помочь:

SELECT v.* 
FROM video v JOIN 
    join_video_category vc 
    ON v.id = bc.id_video 
WHERE vc.ID_CATEGORY = 11 AND v.UPLOADED_DATE >= '2015-01-01' 
ORDER BY v.UPLOADED_DATE DESC 
LIMIT 10; 

Наконец, если это не сработает, попробуйте добавить что-то вроде UPLOADED_DATE в join_video_category. Затем этот запрос должен пылать:

select vc.video_id 
from join_vdeo_category vc 
where vc.ID_CATEGORY = 11 
order by vc.UPLOADED_DATE desc 
limit 10; 

с индексом на join_video_category(id_category, uploaded_date, video_id).

+0

ОК, я хочу добавить UPLOADED_DATE в таблицу join_video_category, спасибо за вашу помощь! – Johann

0

решение # 1: замена "in" на "существует" улучшит производительность, попробуйте выполнить приведенный ниже запрос.

SELECT * FROM video WHERE exists 
(SELECT * FROM join_video_category WHERE ID_CATEGORY=11 AND join_video_category.ID_VIDEO = video.ID) 
ORDER BY UPLOADED_DATE DESC LIMIT 10; 

раствор # 2:

1) создать tem_table

CREATE TABLE TEMP_TABLE AS SELECT * FROM join_video_category WHERE ID_CATEGORY=11; 

2) использовать временную таблицу в растворе # 1

SELECT * FROM video WHERE exists 
    (SELECT * FROM temp_table WHERE temp_table.ID_VIDEO = video.ID) 
    ORDER BY UPLOADED_DATE DESC LIMIT 10; 

удачи !!

0

Если это 1: Многие, не используйте дополнительную таблицу между видео и категорией. Тем не менее, ваш подсчет строк означает, что это много: много.

Если это 1: Многие просто имеют category_id в таблице Video, а затем упрощают все запросы.

Если Много: Много, то обязательно использовать этот шаблон для таблицы перехода:

CREATE TABLE map_video_category (
    video_id ..., 
    category_id ..., 
    PRIMARY KEY(video_id, category_id), -- both ids, one direction 
    INDEX  (category_id, video_id) -- both ids, the other direction 
) ENGINE=InnoDB; -- significantly better than MyISAM on INDEX handling here 

идентификатор, который вы упомянули, это пустая трата времени. Комбинированные клавиши оптимальны для всех ситуаций и улучшают производительность в большинстве ситуаций.

Не использовать IN (SELECT ...); оптимизатор делает плохую работу по ее оптимизации. Перейдите на страницу JOIN, LEFT JOIN, EXISTS или какую-либо другую конструкцию.