Mysql对于Innodb关于ORDER BY使用索引的性能问题

如何提升 ORDER BY 查询速度

通常ORDER BY(对某些列进行排序)语句的性能方面对新人来说很容易被忽略。当然尽管对ORDER BY 的列加索引也不一定能够对性能有所提升!

关于ORDER BY是对我们查询出来的记录按照某种规则进行排序(也就是排序算法)。
如果查询出来的结果集过大的话,将无法再内存中直接进行排序,可能要借助磁盘空间来暂时存储中间结果(凡是跟磁盘挂钩的,速度肯定不会快到哪里去),最后才返回给客户端显示。

通常情况下如果遇到数据量大的时候使用ORDER BY我们可以考虑给ORDER BY的这些列建立一个索引。(但这可能起不到作用,主要看语法,后面说。)

CREATE TABLE player_score (
id int(11) unsigned NOT NULL AUTO_INCREMENT,
type int(11) NOT NULL DEFAULT ‘0’,
score int(11) unsigned NOT NULL DEFAULT ‘0’,
rank int(11) unsigned NOT NULL DEFAULT ‘0’,
other int(11) unsigned NOT NULL DEFAULT ‘0’,
PRIMARY KEY (id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC;

例:我们有一个sql语句如下

SELECT * FROM player_score order by type, score LIMIT 10;

对于这条SQL查询出来的结果集来说,Innodb是先对type类型的值进行排序,如果type值相同再对score进行排序的。
这个步骤有没觉得似曾相识?

是的!他跟我们的索引逻辑是一样的

在我们对type跟score建立索引后(顺序一定要对!!!先type后score,跟语句中一样!!!),并命名为:idx_type_score,这棵B+树是按照type大小排序,相同则按照score排序,完全符合ORDER BY的需求,对建立了索引的字段进行ORDER BY相当于不需要再次进行各种排序了,也不用考虑排序过程中数据量是否过大,是否会在硬盘中暂存,可以直接从索引中取出对应的值,再进行回表操作就可以取出完整数据了。

PS : 回表其实就是自己建立的非聚簇索引中获取对应的主键值,再回到Innodb为我们自动建立的聚簇索引中通过主键来获取完整的记录。
这种操作主要是为了节省空间,不需要每建立一个索引就保存一套完整的数据。

从上面内容引出如下

我们将SQL语句改成这样:

SELECT * FROM player_score order by type, score;

可以看出我们相比前面的SQL少了LIMIT 10

二级索引中获取的每一个主键都需要回调聚簇索引中查询一遍获取完整数据,所以LIMIT很大的时候其实使用索引反而变成了一种累赘!

因为没有了限制,那输出的数据会随着表中数据量的变化而变慢(因为要回表的数据越来越多了),直到最后由查询优化器去决定使用全表查询还是索引查询了。

对于这种情况,使用索引可能并不能提升速度!

进一步改写SQL语句

从上面的SQL语句可以看出,对于数据量大的情况下上面语句建立索引其实并不能起到预期的效果。
我们可以结合自身的需求,是否能将上面的SQL语句改写成如下形式:

SELECT type, score, rank FROM player_score order by type, score;

我们只需要查询type、score、rank三个字段,那在SELECT的时候只查询出需要的这几个字段(当然其他情况其实也是不太推荐使用 * 把所有数据查询出来的),对于这三个字段,我们可以选择使用覆盖索引,将type、score、rank建立为一个索引 idx_type_score_rank
idx_type_score_rank索引的目录项中一个目录页的数据包含以下几个参数

目录页
type
score
rank
id

这是我们再次使用ORDER BY来对type, score进行排序时可以使用idx_type_score_rank索引来进行查找数据(这是联合索引的特性,不了解可以去看看),而且从上面的目录页中可以看出,这棵二级索引中包含了我们想要查找的所有数据,所以就不需要再次通过获取ID后回表来查询聚簇索引数据。

使用覆盖索引能够很好的提升我们的性能,可以很好的避免回表造成的性能损耗。

其他情况

SELECT * FROM player_score order by type ASC, score DESC LIMIT 10;

对type进行升序排序,而对score进行降序排序,对于这种形式Innodb中并不提供索引使用!!!因为这种要达到排序的目的是需要掺杂是否从左到右还是从右到左的算法。这时使用索引可能就体现的稍微有些累赘。而使用全表查询可能来的更快些。

默认都是ASC,只要都使用升序或者降序的话是可以使用索引的。

如果你的MySQL InnoDB表中,where字段有索引,但是在使用order by聚集索引进行排序时仍然很慢,可能是由于以下几个原因导致的: 1. 索引选择不当:虽然你的where字段有索引,但是在order by聚集索引排序时,可能没有使用到合适的索引使用EXPLAIN语句来查看查询计划,确认是否使用了正确的索引。你可以尝试创建一个包含where字段和排序字段的复合索引,以提高查询效率。 2. 数据量过大:如果表中的数据量非常大,即使有合适的索引,仍然可能导致排序操作变慢。考虑通过分页查询或者限制结果集的大小来减少排序的数据量。 3. 硬件性能问题:如果服务器硬件配置较低,例如内存不足或者磁盘IO性能不佳,也可能导致排序操作变慢。确保服务器具备足够的资源以支持高效的排序操作。 4. 查询优化:请检查SQL语句是否存在其他影响性能的因素,例如过多的关联表、不必要的数据类型转换等。优化查询语句可以提高整体性能。 5. 调整配置参数:针对InnoDB引擎,你还可以尝试调整一些相关的配置参数来优化排序操作。例如,增加sort_buffer_size参数的值,提高排序缓冲区的大小。 总之,解决MySQL InnoDB的where字段有索引,但是order by聚集索引排序很慢的问题,需要综合考虑索引选择、数据量、硬件性能、查询优化和配置参数等方面的因素。通过合理的索引设计、优化查询语句和调整配置参数,可以提高排序操作的性能
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值