简体   繁体   English

MySQL使用文件排序慢查询

[英]MySQL slow query using filesort

I have speed problems with a MySQL query. 我在使用MySQL查询时遇到速度问题。 The tables definitions are as follows: 这些表的定义如下:

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;

and

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;

And the query is as follows: 查询如下:

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;

And I get the following with an Explain: 我得到以下解释:

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

The Student table has got about 500,000 records and the college table has 915 rows. “学生”表具有约500,000条记录,“大学”表具有915行。 A third table is used to hold all the locations of the colleges. 第三个表用于存放学院的所有位置。 My query needs to retrieve all the students for a particular location and then sort the results by countup and updated_time. 我的查询需要检索特定位置的所有学生,然后按countup和updated_time对结果进行排序。 I have a composite index on countup and updated_time. 我有一个关于countup和updated_time的综合索引。 I would like to get rid of the filesort but I have not been able to find a satisfactory method. 我想摆脱文件排序,但是我找不到令人满意的方法。

I have considered moving the college_location into the student table so that it can be combined into a composite index. 我考虑过将college_location移到student表中,以便可以将其合并为一个复合索引。 Is there a better solution? 有更好的解决方案吗?

Query below will remove Using temporary; 下面的查询将删除“使用临时”; Using filesort. 使用文件排序。 from the explain so this should run better in thoery.. 从解释上来说,这样应该更有效。

MySQL optimizer is dumb so the trick is to force the optimizer want you want and that is an derived table based on college.college_location = 1. So you can INNER JOIN the result with the student table. MySQL优化器是愚蠢的,因此诀窍在于强制优化器是您想要的,并且这是一个基于college.college_location = 1的派生表。因此,您可以将结果与Student表进行内连接。 And this way MySQL can use the sort key 这样,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

Note the new index in caps lock 注意大写锁定中的新索引

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

Or you can use this if you think it makes more sense or is easier to read. 或者,如果您认为它更有意义或更易于阅读,则可以使用它。 The performance should be the same because the explain explained to me that it is the same. 性能应该是相同的,因为解释向我解释了它是相同的。

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

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

New strategy divide and conquer method Fire more querys to the database what will make use off correct indexes. 新的策略分治法将更多查询发送到数据库,这将使用正确的索引。 And remove the need for an temporary table and filesort. 并且不需要临时表和文件排序。

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
;

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

I can't test this very easily, but try using this student_sort key: 我很难对此进行测试,但是请尝试使用此student_sort密钥:

KEY student_sort ( student_college , countup DESC , updated_time DESC) KEY student_sort ( student_college , counting DESC , updated_time DESC)

Try index: 尝试索引:

KEY student_sort(countup DESC ,updated_time DESC)

Then use STRAIGHT_JOIN and FORCE INDEX: 然后使用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