我有一个运行MySQL 5.5.57的raspberry PI 3 - 这是在RPI上运行的唯一服务。 我的应用程序进行了一个关键查询(如下所示),需要5-7秒才能在MySQL服务器上执行。
我已经做了很多工作来优化索引和FK,但它确实没有多大帮助。当我做一个解释时,我发现它是使用临时文件和文件,我不太懂。
该表有大约30,000行并且正在增长......
这是查询:
SELECT SQL_NO_CACHE distinct `photos`.*
FROM `photos`
LEFT OUTER JOIN `facets` ON `photos`.`id` = `facets`.`photo_id`
WHERE (`photos`.`date_taken` <= '2017-08-24')
AND (photos.status != 1 or photos.status is NULL)
ORDER BY photos.date_taken DESC LIMIT 500 OFFSET 500;
这是表格设置:
CREATE TABLE `photos` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`date_taken` datetime DEFAULT NULL,
`created_at` datetime NOT NULL,
`updated_at` datetime NOT NULL,
`file_extension` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
`file_size` int(11) DEFAULT NULL,
`location_id` bigint(20) DEFAULT NULL,
`make` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
`model` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
`original_height` int(11) DEFAULT NULL,
`original_width` int(11) DEFAULT NULL,
`longitude` decimal(16,10) DEFAULT NULL,
`latitude` decimal(16,10) DEFAULT NULL,
`status` int(11) DEFAULT ''0'',
`phash` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
`org_id` int(11) DEFAULT NULL,
`lg_id` int(11) DEFAULT NULL,
`md_id` int(11) DEFAULT NULL,
`tm_id` int(11) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `index_photos_on_location_id` (`location_id`),
KEY `index_photos_on_date_taken` (`date_taken`),
KEY `index_photos_on_status` (`status`),
KEY `index_photos_on_phash` (`phash`),
CONSTRAINT `fk_rails_47f4e5f105` FOREIGN KEY (`location_id`) REFERENCES `locations` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=25672 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci
当我对查询做一个解释时,这就是我得到的:
+----+-------------+--------+-------+---------------------------------------------------+----------------------------+---------+-------------------+-------+----------------------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+--------+-------+---------------------------------------------------+----------------------------+---------+-------------------+-------+----------------------------------------------+
| 1 | SIMPLE | photos | range | index_photos_on_date_taken,index_photos_on_status | index_photos_on_date_taken | 9 | NULL | 13147 | Using where; Using temporary; Using filesort |
| 1 | SIMPLE | facets | ref | index_facets_on_photo_id | index_facets_on_photo_id | 9 | pt_prod.photos.id | 1 | Using index; Distinct |
+----+-------------+--------+-------+---------------------------------------------------+----------------------------+---------+-------------------+-------+----------------------------------------------+
查询有时会扩展为:
SELECT DISTINCT `photos`.*
FROM `photos`
LEFT OUTER JOIN `facets` ON `photos`.`id` = `facets`.`photo_id`
LEFT OUTER JOIN `tags` ON `facets`.`source_id` = `tags`.`id`
LEFT OUTER JOIN `comments` ON `facets`.`source_id` = `comments`.`id`
WHERE `photos`.`date_taken` >= '2017-01-25'
AND `photos`.`date_taken` <= '2018-01-10'
AND `locations`.`country_id` = 16
AND `locations`.`city_id` = 21
OR `facets`.`source_id` = 9 AND `facets`.`type` = 'AlbumFacet'
OR `facets`.`source_id` = 9 AND `facets`.`type` = 'TagFacet'
答案 0 :(得分:2)
这是对问题的原始版本的回答。
您的查询仅使用第一个表中的列。我会把它写成:
SELECT SQL_NO_CACHE `photos`.*
FROM `photos` p
LEFT OUTER JOIN `facets` ON `photos`.`id` = `facets`.`photo_id`
WHERE (p.`date_taken` <= '2017-08-24') AND (NOT p.status <=> 1) AND
EXISTS (SELECT 1 FROM facets f WHERE pid = f.photo_id)
ORDER BY p.date_taken DESC
LIMIT 500 OFFSET 500;
删除SELECT DISTINCT
应该有点胜利。您还应该在facets(photo_id)
上有一个索引。
(date_taken, status)
上的索引可能有所帮助。但是,目前还不清楚你的条件是多么有选择性,因此照片索引可能没什么用处。