order by使查询变慢

时间:2015-08-22 14:14:21

标签: mysql sql performance database-indexes

我有两张桌子:

video (ID, TITLE, ..., UPLOADED_DATE)
join_video_category (ID (not used), ID_VIDEO_ ID_CATEGORY)
视频中的

行:4 500 000 | 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个最新视频时,我的查询大约需要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,PRIMARY ON ID视频和join_video_category的索引。

我在查询中使用JOIN对其进行了测试,结果相同。

3 个答案:

答案 0 :(得分:1)

首先,比较是针对两个非常不同的查询。第一个视频遇到它们时会返回一堆视频。第二个必须阅读所有视频,然后对它们进行排序。

尝试将其重写为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)

答案 1 :(得分: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;

祝你好运!!

答案 2 :(得分:0)

如果是1:很多,请不要在视频和类别之间使用额外的表格。但是,你的行数意味着它很多:很多。

如果它是1:很多,只需在视频表中使用category_id,然后简化所有查询。

如果它是多个:很多,那么一定要使用这个模式作为联结表:

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

您提到的ID是浪费。复合键适用于所有情况,并可在大多数情况下提高性能。

不要使用IN ( SELECT ... );优化器在优化它方面做得很差。更改为JOINLEFT JOINEXISTS或其他一些构造。