我有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
移到学生表中,以便将它组合成一个复合索引。有更好的解决方案吗?
答案 0 :(得分:4)
下面的查询将删除使用临时;使用filesort。从解释,所以这应该在理论上更好..
MySQL优化器是愚蠢的,所以诀窍是强制优化器想要你想要的,这是一个基于college.college_location = 1的派生表。 因此,您可以使用学生表INNER JOIN结果。 这样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
新策略分治方法 向数据库发出更多查询,以便使用正确的索引。 并且不需要临时表和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
;
答案 1 :(得分:0)
我无法轻松测试,但请尝试使用此student_sort
键:
KEY
{student_sort {1}} {student_college {1}} {计数进位{1}} {updated_time {1}}
答案 2 :(得分:0)
尝试索引:
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;