我收到了这个问题:
SELECT user_id
FROM basic_info
WHERE age BETWEEN 18 AND 22 AND gender = 0
ORDER BY rating
LIMIT 50
该表看起来像(并且它包含大约700k行):
CREATE TABLE IF NOT EXISTS `basic_info` (
`user_id` mediumint(8) unsigned NOT NULL auto_increment,
`gender` tinyint(1) unsigned NOT NULL default '0',
`age` tinyint(2) unsigned NOT NULL default '0',
`rating` smallint(5) unsigned NOT NULL default '0',
PRIMARY KEY (`user_id`),
KEY `tmp` (`gender`,`rating`),
) ENGINE=MyISAM;
查询本身已经过优化,但它必须走大约20万行来完成他的工作。 这是解释输出:
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE basic_info ref tmp,age tmp 1 const 200451 Using where
是否可以优化查询,使其不会超过200k行?
谢谢!
答案 0 :(得分:7)
有两个有用的索引可以帮助您进行此查询:
KEY gender_age (gender, age)
- 此索引既可以满足gender=0
条件,也可以满足age BETWEEN 18 AND 22
。但是,因为age
字段上有范围条件,所以将rating
列添加到索引中将不会给出排序结果 - 因此MySQL将选择所有匹配的行 - - 忽略你的LIMIT条款 - 并且无论如何都要做一个额外的 filesort 。
KEY gender_rating (gender, rating)
- 您已有的索引;此索引可以满足gender=0
条件,并按rating
检索已经排序的数据 。但是,数据库必须使用gender=0
扫描所有元素,并消除那些不在范围内的人age BETWEEN 18 AND 22
如果上述内容对您没有帮助,则始终可以更改架构。一种这样的方法是通过定义年龄组列将age BETWEEN
条件转换为相等条件;例如,0-12岁的年龄组为1岁,12-18岁的年龄组为2岁等。
这样,索引为(gender, agegroup, rating)
且查询为WHERE gender=0 AND agegroup=3 ORDER BY rating
将从索引中检索所有结果并已排序。在这种情况下,LIMIT子句应仅从表中获取50个条目,而不再是。
答案 1 :(得分:1)
扩展您tmp
- 键以包含age
- 列:
KEY `tmp` (`age`,`gender`,`rating`)
答案 2 :(得分:1)
尝试使用InnoDB来提高性能?
基准here