MySQL 建立索引的时候如何排序?

比如 students表里面有 ageid,sex三个字段,现在有一天sql是这样的 select * from students where sex=1 and age >10 order by id desc,我改怎么建立这个索引顺序,让这个三个字段都能用上?

《L02 从零构建论坛系统》
以构建论坛项目 LaraBBS 为线索,展开对 Laravel 框架的全面学习。应用程序架构思路贴近 Laravel 框架的设计哲学。
《G01 Go 实战入门》
从零开始带你一步步开发一个 Go 博客项目,让你在最短的时间内学会使用 Go 进行编码。项目结构很大程度上参考了 Laravel。
最佳答案

age、sex 建立联合索引。 id,本身是主键。

4年前 评论
panda-sir 4年前
讨论数量: 17

age、sex 建立联合索引。 id,本身是主键。

4年前 评论
panda-sir 4年前

@轻描淡写 id、age、sex 用这三个字段建立联合索引?

4年前 评论

@FreeMason 想在一个那个查询里面用到这三个字段建立的索引。不知道能不能建

4年前 评论

搞了一会儿,没想到好的方案

4年前 评论

@轻描淡写 三个字段分别建立索引?“三个字段建立的索引”,建立什么索引? 联合索引 + 主键 在你 sql 里不是都能用到索引吗?

4年前 评论

不是分别,一个索引三个字段 @FreeMason

4年前 评论

@轻描淡写 以你给的 sql,id 只是用在 排序 ,这三个字段建立联合索引,没必要,id 已经是主键了。

4年前 评论

我也是建立的sex,age ,explain显示用到了 这两个字段建立的索引,但是order by id desc 就用不上了主键索引了。

4年前 评论

@轻描淡写 把你查询的 SQL 与 explain 截图出来

4年前 评论

id,sex,age 组合索引,where id > 0 and sex = 1 and age > 10 ,好像order by 要用索引必须再where条件中存在

4年前 评论

@轻描淡写 @FreeMason 表引擎在 innodb的情况下建立 agesex 的联合索引即可,innodb会在建立索引时生成btree数据结构,这个数据结构上会隐式的加上主键,搜索时在这个索引上搜索来找到主键(索引顺序是age,sex,id),在通过主键找到数据。文中的SQL语句select * from students where sex=1 and age >10 order by id desc 使用不到id的原因,是因为age是范围查找,如果是age=xx就可以用的上了,题主可以去找些关于表引擎的介绍(高性能MySQL第五章 5.3.5节)

4年前 评论

@anniversary 我知道范围之后索引会失效,我也尝试建立id sex age的索引,可是也没有效果。后来就建立了sex age的索引,然后按照age排序了(实际情况中 age 字段是 created_at,所以按照创建时间和按照主键 id 排序应该是同一种结果吧,速度确实快了很多)

4年前 评论
anniversary 4年前
FM 4年前
轻描淡写 (作者) (楼主) 4年前
轻描淡写 (作者) (楼主) 4年前
轻描淡写 (作者) (楼主) 4年前
FM 4年前
FM 4年前
轻描淡写 (作者) (楼主) 4年前

@anniversary

以下回复可能有需要更正的地方

“表引擎在 innodb 的情况下建立 age、sex 的联合索引即可,innodb 会在建立索引时生成 btree 数据结构,这个数据结构上会隐式的加上主键“

这是主键索引与二级索引之间的关联 ID,个人理解不是隐式,而是显式

“搜索时在这个索引上搜索来找到主键 (索引顺序是 age,sex,id),在通过主键找到数据”

1、索引顺序更准确的应该是 age_sex,id
2、是否需要通过主键找到数据,取决于是否需要回表,如果索引上已经可以拿到查询的所有数据,则不需
要回表

”文中的 SQL 语句 select * from students where sex=1 and age >10 order by id desc 使用不到 id 的原因,是因为 age 是范围查找,如果是 age=xx 就可以用的上了,题主可以去找些关于表引擎的介绍 (高性能 MySQL 第五章 5.3.5 节)“

1、《高性能 MySQL》第五章确实有关于 order 最左、第一个范围等不能使用索引等说明。
2、结合自己的知识与测试后的结果是,范围查询 order by id,未出现 using filesort 等 order 未使用到索引的情况。

// 创建表
CREATE TABLE `t` (
  `id` int(11) NOT NULL,
  `city` varchar(16) NOT NULL,
  `name` varchar(16) NOT NULL,
  `age` int(11) NOT NULL,
  PRIMARY KEY (`id`),
  KEY `city` (`city`)
) ENGINE=InnoDB;

// 执行的 SQL
desc select id,city from t where city in('杭州','北京') order by 'id'

执行结果

Laravel

以下是自己整理的 MySQL order 是否能使用到索引的条件,当然还有其它因素:

1、排序的字段是 有序

2、优化器 认为走索引更快,order 最终才会走索引

3、where 与 order 会共同影响(这方面的知识欠缺)

4年前 评论
anniversary 4年前
FM (作者) 4年前
FM (作者) 4年前

@轻描淡写 初步测试了解到,MySQL order 字段为时间类型时,order 索引确实未用到。非时间类型还未测试有这种情况

4年前 评论

@FreeMason

file

这是sql 和 explain 和添加的索引,order by的是主键

file

但是当我查询三个月之前的数据时 explain 成这样了(使用的索引变了),就只变了时间。(上面是查询七天前的数据,单表430万数据)

Laravel

4年前 评论

@轻描淡写 分析是在 优化器 这里优化时,选择了不同的索引,你把这两个不同的时间的数据的区分度计算下。

4年前 评论

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!