繁体   English   中英

MySQL使用文件排序慢查询

[英]MySQL slow query using filesort

我在使用MySQL查询时遇到速度问题。 这些表的定义如下:

CREATE TABLE IF NOT EXISTS `student` (
  `student_id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `forename` varchar(30) NOT NULL,
  `updated_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  `surname` varchar(50) NOT NULL,
  `student_college` int(11) DEFAULT NULL,
  `countup` smallint(5) unsigned DEFAULT NULL, 
  PRIMARY KEY (`student_id`),
  KEY `countup` (`countup`),
  KEY `student_sort` (`countup`,`updated_time`),
  KEY `student_college` (`student_college`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

CREATE TABLE IF NOT EXISTS `college` (
  `college_id` int(11) NOT NULL AUTO_INCREMENT,
  `college_name` varchar(100) NOT NULL DEFAULT 'Centre Name',
  `college_location` int(11) DEFAULT NULL,
  PRIMARY KEY (`college_id`),
  KEY `college_location` (`college_location`),
  KEY `college_name` (`college_name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

查询如下:

SELECT *
FROM student
JOIN college ON student.student_college = college.college_id
WHERE  
college_location = 1
ORDER BY student.countup desc, student.updated_time desc
LIMIT 15;

我得到以下解释:

id select_type table   type possible_keys              key              key_len    ref                           rows Extra
1  SIMPLE      college ref  "PRIMARY,college_location" college_location 5          const                         915  Using where; Using temporary; Using filesort
1  SIMPLE      student ref  student_college            student_college  5          speed_test.college.college_id 50   Using where

“学生”表具有约500,000条记录,“大学”表具有915行。 第三个表用于存放学院的所有位置。 我的查询需要检索特定位置的所有学生,然后按countup和updated_time对结果进行排序。 我有一个关于countup和updated_time的综合索引。 我想摆脱文件排序,但是我找不到令人满意的方法。

我考虑过将college_location移到student表中,以便可以将其合并为一个复合索引。 有更好的解决方案吗?

下面的查询将删除“使用临时”; 使用文件排序。 从解释上来说,这样应该更有效。

MySQL优化器是愚蠢的,因此诀窍在于强制优化器是您想要的,并且这是一个基于college.college_location = 1的派生表。因此,您可以将结果与Student表进行内连接。 这样,MySQL可以使用排序键

SELECT 
 *
FROM 
 student
INNER JOIN (
    SELECT 
     college_id
    FROM 
     college
    WHERE
     college.college_location = 1  
  ) college
ON student.student_college = college.college_id
ORDER BY
    student.countup DESC
  , student.updated_time DESC

注意大写锁定中的新索引

参见演示http://sqlfiddle.com/#!2/05c8a/1

或者,如果您认为它更有意义或更易于阅读,则可以使用它。 性能应该是相同的,因为解释向我解释了它是相同的。

SELECT 
 * 
FROM (
  SELECT 
    college_id
  FROM 
    college
  WHERE
    college.college_location = 1  
) 
  college

INNER JOIN
 student 

ON
 student.student_college = college.college_id

ORDER BY
    student.countup DESC
  , student.updated_time DESC

参见演示http://sqlfiddle.com/#!2/05c8a/23

新的策略分治法将更多查询发送到数据库,这将使用正确的索引。 并且不需要临时表和文件排序。

SET @college_ids = NULL; 

SELECT
  GROUP_CONCAT(college_id)
FROM
  college
WHERE
  college_location = 1
GROUP BY
  college_location ASC
INTO @college_ids;

SELECT 
 *
FROM 
 student
WHERE 
 student.student_college IN(@college_ids)
ORDER BY
    student.countup DESC
  , student.updated_time DESC
;

参见演示http://sqlfiddle.com/#!2/454b3/61

我很难对此进行测试,但是请尝试使用此student_sort密钥:

KEY student_sort ( student_college , counting DESC , updated_time DESC)

尝试索引:

KEY student_sort(countup DESC ,updated_time DESC)

然后使用STRAIGHT_JOIN和FORCE INDEX:

SELECT *
FROM student force index(student_sort) STRAIGHT_JOIN 
     college 
         ON student.student_college = college.college_id
WHERE college_location = 1
ORDER BY student.countup desc, 
         student.updated_time desc
LIMIT 15;

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM