谈谈MySQL中的降序索引 order by id DESC / ASC
今天这篇主要讲order by 语句中的多个字段asc desc的问题。mysql5中,索引存储的排序方式是ASC的,没有DESC的索引。现在能够理解为啥order by 默认是按照ASC来排序的了吧?虽然索引是ASC的,但是也可以反向进行检索,就相当于DESC了。如果您在ORDER BY 语句中使用了 DESC排序,mysql确实会反向进行检索。在理论上,反向检索与正向检索的速度一样的快。但是在某些操作系统上面,并不支持反向的read-ahead预读,所以反向检索会略慢。由于设计的原因,在myisam引擎中,反向的检索速度比正向检索要慢得多。如果ORDER BY 子句中同时出现ASC和DESC,会是怎样的情况呢?
OEDER BY price ASC, date DESC LIMIT 0,10;
而且在 (price,date)上有一个组合索引。
explain之后可以发现,虽然用到了这个索引,但是仍然会用到filesort,说明只是使用到了索引中price的ASC排序。
看一个实际的例子吧:
discuz 7.2 gbk版,主题列表:cdb_threads。
mysql> SHOW CREATE TABLE cdb_threads;
| cdb_threads | CREATE TABLE `cdb_threads` (
`tid` mediumint(8) UNSIGNED NOT NULL AUTO_INCREMENT,
`fid` smallint(6) UNSIGNED NOT NULL DEFAULT '0',
`iconid` smallint(6) UNSIGNED NOT NULL DEFAULT '0',
`typeid` smallint(6) UNSIGNED NOT NULL DEFAULT '0',
`sortid` smallint(6) UNSIGNED NOT NULL DEFAULT '0',
`readperm` tinyint(3) UNSIGNED NOT NULL DEFAULT '0',
`price` smallint(6) NOT NULL DEFAULT '0',
`author` char(15) NOT NULL,
`authorid` mediumint(8) UNSIGNED NOT NULL DEFAULT '0',
`subject` char(80) NOT NULL,
`dateline` int(10) UNSIGNED NOT NULL DEFAULT '0',
`lastpost` int(10) UNSIGNED NOT NULL DEFAULT '0',
`lastposter` char(15) NOT NULL,
`views` int(10) UNSIGNED NOT NULL DEFAULT '0',
`replies` mediumint(8) UNSIGNED NOT NULL DEFAULT '0',
`displayorder` tinyint(1) NOT NULL DEFAULT '0',
`highlight` tinyint(1) NOT NULL DEFAULT '0',
`digest` tinyint(1) NOT NULL DEFAULT '0',
`rate` tinyint(1) NOT NULL DEFAULT '0',
`special` tinyint(1) NOT NULL DEFAULT '0',
`attachment` tinyint(1) NOT NULL DEFAULT '0',
`moderated` tinyint(1) NOT NULL DEFAULT '0',
`closed` mediumint(8) UNSIGNED NOT NULL DEFAULT '0',
`itemid` mediumint(8) UNSIGNED NOT NULL DEFAULT '0',
`supe_pushstatus` tinyint(1) NOT NULL DEFAULT '0',
`sgid` mediumint(8) UNSIGNED NOT NULL DEFAULT '0',
`recommends` smallint(6) NOT NULL,
`recommend_add` smallint(6) NOT NULL,
`recommend_sub` smallint(6) NOT NULL,
`heats` int(10) UNSIGNED NOT NULL DEFAULT '0',
`status` smallint(6) UNSIGNED NOT NULL DEFAULT '0',
PRIMARY KEY (`tid`),
KEY `digest` (`digest`),
KEY `displayorder` (`fid`,`displayorder`,`lastpost`),
KEY `typeid` (`fid`,`typeid`,`displayorder`,`lastpost`),
KEY `sgid` (`fid`,`sgid`),
KEY `sortid` (`sortid`),
KEY `recommends` (`recommends`),
KEY `heats` (`heats`),
KEY `authorid` (`authorid`)
) ENGINE=InnoDB AUTO_INCREMENT=330109 DEFAULT CHARSET=gbk |
fid开头的组合索引有三个:
KEY `displayorder` (`fid`,`displayorder`,`lastpost`),
KEY `typeid` (`fid`,`typeid`,`displayorder`,`lastpost`),
KEY `sgid` (`fid`,`sgid`),
我们用fid和displayorder字段来做排序。
先看order by fid ASC,displayorder ASC的情况:
mysql> EXPLAIN SELECT * FROM cdb_threads WHERE fid IN(1,3,5) ORDER BY fid ASC,displayorder ASC;
+----+-------------+-------------+-------+--------------------------+--------------+---------+------+-------+-------------+
| id | select_type | TABLE | type | possible_keys | KEY | key_len | ref | rows | Extra |
+----+-------------+-------------+-------+--------------------------+--------------+---------+------+-------+-------------+
| 1 | SIMPLE | cdb_threads | range | displayorder,typeid,sgid | displayorder | 2 | NULL | 12728 | USING WHERE |
+----+-------------+-------------+-------+--------------------------+--------------+---------+------+-------+-------------+
1 row IN SET (0.00 sec)
再看ORDER BY fid DESC, displayorder DESC的情况:
mysql> EXPLAIN SELECT * FROM cdb_threads WHERE fid IN(1,3,5) ORDER BY fid DESC,displayorder DESC;
+----+-------------+-------------+-------+--------------------------+--------------+---------+------+-------+-------------+
| id | select_type | TABLE | type | possible_keys | KEY | key_len | ref | rows | Extra |
+----+-------------+-------------+-------+--------------------------+--------------+---------+------+-------+-------------+
| 1 | SIMPLE | cdb_threads | range | displayorder,typeid,sgid | displayorder | 2 | NULL | 12728 | USING WHERE |
+----+-------------+-------------+-------+--------------------------+--------------+---------+------+-------+-------------+
1 row IN SET (0.00 sec)
这两种情况下,使用到的KEY都是 KEY `displayorder` (`fid`,`displayorder`,`lastpost`), 没有进行filesort,很完美。
再来看一个DESC,另外一个ASC的情况:
mysql> EXPLAIN SELECT * FROM cdb_threads WHERE fid IN(1,3,5) ORDER BY fid DESC,displayorder ASC;
+----+-------------+-------------+-------+--------------------------+------+---------+------+------+-----------------------------+
| id | select_type | TABLE | type | possible_keys | KEY | key_len | ref | rows | Extra |
+----+-------------+-------------+-------+--------------------------+------+---------+------+------+-----------------------------+
| 1 | SIMPLE | cdb_threads | range | displayorder,typeid,sgid | sgid | 2 | NULL | 6512 | USING WHERE; USING filesort |
+----+-------------+-------------+-------+--------------------------+------+---------+------+------+-----------------------------+
1 row IN SET (0.00 sec)
mysql> EXPLAIN SELECT * FROM cdb_threads WHERE fid IN(1,3,5) ORDER BY fid ASC,displayorder DESC;
+----+-------------+-------------+-------+--------------------------+------+---------+------+------+-----------------------------+
| id | select_type | TABLE | type | possible_keys | KEY | key_len | ref | rows | Extra |
+----+-------------+-------------+-------+--------------------------+------+---------+------+------+-----------------------------+
| 1 | SIMPLE | cdb_threads | range | displayorder,typeid,sgid | sgid | 2 | NULL | 6512 | USING WHERE; USING filesort |
+----+-------------+-------------+-------+--------------------------+------+---------+------+------+-----------------------------+
1 row IN SET (0.00 sec)
这两次使用到的key是 KEY `sgid` (`fid`,`sgid`), 由于我们并没有涉及到sgid,所以只用到了fid的索引。。。 至于displayorder字段怎样排序,用的是filesort。肯定比直接使用索引要慢多了。
如果可以搞一个fid ASC, displayorder DESC的组合索引,那就方便多了。事实上mysql不支持这么做啦。
既然mysql不支持这种方式,那我们只好用其它方法解决这个问题。
创建一个新的字段,叫做reverse_displayorder。 此字段中保存的值为 displayorder字段的值乘以-1。
于是 order by fid ASC, displayorder DESC 就可以转化成 order by fid ASC, reverse_displayorder ASC了。
如果是mysql 5.0或之后的版本,只要创建一个触发器(trigger)来自动更新reverse_displayorder的值就可以了,程序都不用大改。
虽然discuz没有这样做,但是MediaWiki确实是这样设计的。
谈谈MySQL中的降序索引 order by id DESC / ASC的更多相关文章
- MySQL 8 新特性之降序索引
MySQL 8.0终于支持降序索引了.其实,从语法上,MySQL 4就支持了,但正如官方文档所言,"they are parsed but ignored",实际创建的还是升序索引 ...
- MySQL8新增降序索引
MySQL8新增降序索引 桃花坞里桃花庵,桃花庵里桃花仙.桃花仙人种桃树,又摘桃花卖酒钱. 一.MySQL5.7 降序索引 MySQL在语法上很早就已经支持降序索引,但实际上创建的却仍然是升序索引,如 ...
- [20181124]关于降序索引问题3.txt
[20181124]关于降序索引问题3.txt --//链接:blog.itpub.net/267265/viewspace-2221425/,探讨降序索引中索引的键值.--//实际上使用函数sys_ ...
- [20181124]关于降序索引问题2.txt
[20181124]关于降序索引问题2.txt --//链接:blog.itpub.net/267265/viewspace-2221425/,探讨降序索引中索引的键值.--//实际上使用函数sys_ ...
- [20191218]降序索引疑问4.txt
[20191218]降序索引疑问4.txt --//前几天优化一个项目,我发现许多表里面有有隐含字段,一般开发很少建立函数索引.我自己检查发现里面存在大量的降序索引.--//我感觉有点奇怪,为什么开发 ...
- [20190910]关于降序索引问题5.txt
[20190910]关于降序索引问题5.txt --//测试了索引TERM使用0xfe表示,回想到以前遇到降序索引的特殊字符编码问题,现在可是忘得一干二净.--//现在想想当时自己怎么猜测出来的,^_ ...
- 谈谈MySQL中的锁
谈谈MySQL中的锁 锁的定义 在生活中锁的例子就非常多了,所以应该很容易理解锁的含义.在计算机领域,可以这样来概述,锁是计算机协调多个进行进程并发访问某一资源的机制. 在数据库中,锁也是一个 ...
- Mysql中主键与索引
摘自: https://www.cnblogs.com/wicub/p/5898286.html 一.什么是索引?索引用来快速地寻找那些具有特定值的记录,所有MySQL索引都以B-树的形式保存.如果没 ...
- mysql 利用延迟关联优化查询(select * from your_table order by id desc limit 2000000,20)
其实在我们的工作中类似,select * from your_table order by id desc limit 2000000,20会经常遇见,比如在分页中就很常见. 如果我们的sql中出现这 ...
随机推荐
- 标记,上传并下载自己创建的镜像 image
1. 首先使用 docker images 查看已有镜像: 2. 获得 docker-whale 的 IMAGE ID,然后为 docker-whale 镜像 image 打上标签 Tag.使用命令: ...
- Knowledge Tracing -- 基于贝叶斯的学生知识点追踪(BKT)
目前,教育领域通过引入人工智能的技术,使得在线的教学系统成为了智能教学系统(ITS),ITS不同与以往的MOOC形式的课程.ITS能够个性化的为学生制定有效的 学习路径,通过根据学生的答题情况追踪学生 ...
- 常见HTTP状态码(200、301、302、500等)解说
对网站管理工作者来说有个词不陌生,HTTP状态码,它是用以表示网页服务器HTTP响应状态的3位数字代码.状态码的第一个数字代表了响应的五种状态之一. 1XX系列:指定客户端应相应的某些动作,代表请求已 ...
- Dubbo学习笔记9:Dubbo服务提供方启动流程源码分析
首先我们通过一个时序图,直观看下Dubbo服务提供方启动的流程: 在<Dubbo整体框架分析>一文中我们提到,服务提供方需要使用ServiceConfig API发布服务,具体是调用代码( ...
- Spring RedisTemplate操作-String操作(2)
@Autowired @Resource(name="redisTemplate") private RedisTemplate<String, String> rt; ...
- 小记 HTML5 file对象
<input type="file" id="myfile" multiple> 这是个很普通的 file 上传组件,multiple 是支持多选, ...
- 控制台console对象常用的一些方法
console.log():调试中最常用的方法,用于在控制台窗口显示信息. console.log(123); console.warn():输出信息时,在最前面加一个黄色三角,表示警告 consol ...
- mysql开启远程连接及本地连接
问题描述 在本机windows上连接linux服务器上的mysql报错:host'XXX' is not allowed to connect to this mysql server. 这个错误是由 ...
- HDU 2054 又见GCD
又见GCD Time Limit: 1000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) Total Subm ...
- str和unicode类
在py2中,分为两类,str和unicode 而在py3中,分为两类,byte和str py2中的str等同于py3中的byte 首先明确一点,我们编辑好一段文本,python并不知道我们的文本是以什 ...