MySQL通过连接和wheres优化排序

时间:2017-08-30 10:47:08

标签: mysql ruby-on-rails

我有这个问题:

SELECT SQL_NO_CACHE  DISTINCT `photos`.* 
FROM `photos` 
INNER JOIN `locations` ON `photos`.`location_id` = `locations`.`id` 
LEFT OUTER JOIN `albums_photos` ON `photos`.`id` = `albums_photos`.`photo_id` 
LEFT OUTER JOIN `facets` ON `photos`.`id` = `facets`.`photo_id` 
LEFT OUTER JOIN `source_tags` ON `facets`.`source_id` = `source_tags`.`id` 
LEFT OUTER JOIN `source_comments` ON `facets`.`source_id` = `source_comments`.`id` 
WHERE (`photos`.`date_taken` <= '2017-08-24') 
AND (photos.status != 1 or photos.status is NULL) 
ORDER BY `photos`.`date_taken` DESC 
LIMIT 75 
OFFSET 0

需要6-7秒才能运行。当我拿出Order by子句时:

SELECT SQL_NO_CACHE  DISTINCT `photos`.* 
FROM `photos` 
INNER JOIN `locations` ON `photos`.`location_id` = `locations`.`id` 
LEFT OUTER JOIN `albums_photos` ON `photos`.`id` = `albums_photos`.`photo_id` 
LEFT OUTER JOIN `facets` ON `photos`.`id` = `facets`.`photo_id` 
LEFT OUTER JOIN `source_tags` ON `facets`.`source_id` = `source_tags`.`id` 
LEFT OUTER JOIN `source_comments` ON `facets`.`source_id` = `source_comments`.`id` 
WHERE (`photos`.`date_taken` <= '2017-08-24') 
AND (photos.status != 1 or photos.status is NULL) 
LIMIT 75 
OFFSET 0

运行需要0.025秒。所以显然没有优化的东西。 我在照片上有这些索引

Table, Non_unique, Key_name, Seq_in_index, Column_name, Collation, Cardinality, Sub_part, Packed, Null, Index_type, Comment, Index_comment
photos, 0, PRIMARY, 1, id, A, 21069, , , , BTREE, , 
photos, 1, index_photos_on_location_id, 1, location_id, A, 468, , , YES, BTREE, , 
photos, 1, index_photos_on_date_taken, 1, date_taken, A, 21069, , , YES, BTREE, , 
photos, 1, index_photos_on_status, 1, status, A, 2, , , YES, BTREE, , 
photos, 1, index_photos_on_phash, 1, phash, A, 21069, , , YES, BTREE, , 

照片按照以下方式设置:

Field, Type, Null, Key, Default, Extra
id, bigint(20), NO, PRI, , auto_increment
date_taken, datetime, YES, MUL, , 
created_at, datetime, NO, , , 
updated_at, datetime, NO, , , 
file_extension, varchar(255), YES, , , 
file_size, int(11), YES, , , 
location_id, bigint(20), YES, MUL, , 
make, varchar(255), YES, , , 
model, varchar(255), YES, , , 
original_height, int(11), YES, , , 
original_width, int(11), YES, , , 
longitude, decimal(16,10), YES, , , 
latitude, decimal(16,10), YES, , , 
status, int(11), YES, MUL, 0, 
phash, varchar(255), YES, MUL, , 
org_id, int(11), YES, , , 
lg_id, int(11), YES, , , 
md_id, int(11), YES, , , 
tm_id, int(11), YES, , , 

我该怎么办?我应该在我的应用程序(rails或JS)中进行排序吗?

- 编辑 -

我应该补充一点,当我取出所有连接但按顺序离开时间下降到一秒以下。让我觉得我需要一个跨连接列的索引和date_taken ??

SELECT SQL_NO_CACHE  DISTINCT `photos`.* 
FROM `photos` 
WHERE (`photos`.`date_taken` <= '2017-08-24') 
AND (photos.status != 1 or photos.status is NULL) 
#AND (`photos`.`date_taken` is not null)
ORDER BY `photos`.`date_taken` DESC 
LIMIT 75 
OFFSET 0;

2 个答案:

答案 0 :(得分:2)

如果表格包含pk(例如:id auto_increment),则distinct photos.*无效 每行ID与其他行不同

在条件

中删除unuseful()

并记住在检索和排序行之后应用限制(对于此尝试删除限制和测试偏移量)

SELECT SQL_NO_CACHE   `photos`.* 
FROM `photos` 
INNER JOIN `locations` ON `photos`.`location_id` = `locations`.`id` 
LEFT JOIN `albums_photos` ON `photos`.`id` = `albums_photos`.`photo_id` 
LEFT JOIN `facets` ON `photos`.`id` = `facets`.`photo_id` 
LEFT JOIN `source_tags` ON `facets`.`source_id` = `source_tags`.`id` 
LEFT JOIN `source_comments` ON `facets`.`source_id` = `source_comments`.`id` 
WHERE `photos`.`date_taken` <= '2017-08-24'
AND  (photos.status != 1 or photos.status is NULL) 
ORDER BY `photos`.`date_taken` DESC 
LIMIT 75 
OFFSET 0

确保所有连接columun和外键都有正确的索引 以及photos.date_takenphotos.status

上的所有正确索引

您还可以使用复合索引(photos.date_taken ,photos.status)

答案 1 :(得分:0)

尝试这样。面对类似的问题并修复它。

SELECT * FROM(
SELECT SQL_NO_CACHE  DISTINCT `photos`.* 
FROM `photos` 
INNER JOIN `locations` ON `photos`.`location_id` = `locations`.`id` 
LEFT OUTER JOIN `albums_photos` ON `photos`.`id` = `albums_photos`.`photo_id` 
LEFT OUTER JOIN `facets` ON `photos`.`id` = `facets`.`photo_id` 
LEFT OUTER JOIN `source_tags` ON `facets`.`source_id` = `source_tags`.`id` 
LEFT OUTER JOIN `source_comments` ON `facets`.`source_id` = `source_comments`.`id` 
WHERE (`photos`.`date_taken` <= '2017-08-24') 
AND (photos.status != 1 or photos.status is NULL)
)ORDER BY `photos`.`date_taken` DESC 
LIMIT 75 
OFFSET 0