今天这篇主要讲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的更多相关文章

  1. MySQL 8 新特性之降序索引

    MySQL 8.0终于支持降序索引了.其实,从语法上,MySQL 4就支持了,但正如官方文档所言,"they are parsed but ignored",实际创建的还是升序索引 ...

  2. MySQL8新增降序索引

    MySQL8新增降序索引 桃花坞里桃花庵,桃花庵里桃花仙.桃花仙人种桃树,又摘桃花卖酒钱. 一.MySQL5.7 降序索引 MySQL在语法上很早就已经支持降序索引,但实际上创建的却仍然是升序索引,如 ...

  3. [20181124]关于降序索引问题3.txt

    [20181124]关于降序索引问题3.txt --//链接:blog.itpub.net/267265/viewspace-2221425/,探讨降序索引中索引的键值.--//实际上使用函数sys_ ...

  4. [20181124]关于降序索引问题2.txt

    [20181124]关于降序索引问题2.txt --//链接:blog.itpub.net/267265/viewspace-2221425/,探讨降序索引中索引的键值.--//实际上使用函数sys_ ...

  5. [20191218]降序索引疑问4.txt

    [20191218]降序索引疑问4.txt --//前几天优化一个项目,我发现许多表里面有有隐含字段,一般开发很少建立函数索引.我自己检查发现里面存在大量的降序索引.--//我感觉有点奇怪,为什么开发 ...

  6. [20190910]关于降序索引问题5.txt

    [20190910]关于降序索引问题5.txt --//测试了索引TERM使用0xfe表示,回想到以前遇到降序索引的特殊字符编码问题,现在可是忘得一干二净.--//现在想想当时自己怎么猜测出来的,^_ ...

  7. 谈谈MySQL中的锁

    谈谈MySQL中的锁 锁的定义 ​ 在生活中锁的例子就非常多了,所以应该很容易理解锁的含义.在计算机领域,可以这样来概述,锁是计算机协调多个进行进程并发访问某一资源的机制. ​ 在数据库中,锁也是一个 ...

  8. Mysql中主键与索引

    摘自: https://www.cnblogs.com/wicub/p/5898286.html 一.什么是索引?索引用来快速地寻找那些具有特定值的记录,所有MySQL索引都以B-树的形式保存.如果没 ...

  9. mysql 利用延迟关联优化查询(select * from your_table order by id desc limit 2000000,20)

    其实在我们的工作中类似,select * from your_table order by id desc limit 2000000,20会经常遇见,比如在分页中就很常见. 如果我们的sql中出现这 ...

随机推荐

  1. HGOI 20181103 题解

    problem:把一个可重集分成两个互异的不为空集合,两个集合里面的数相乘的gcd为1(将集合中所有元素的质因数没有交集) solution:显然本题并不是那么容易啊!考场上想了好久.. 其实转化为上 ...

  2. 解题:CF960G Bandit Blues & FJOI 2016 建筑师

    题面1 题面2 两个题推导是一样的,具体实现不一样,所以写一起了,以FJOI 2016 建筑师 的题面为标准 前后在组合意义下一样,现在只考虑前面,可以发现看到的这a个建筑将这一段划分成了a-1个区间 ...

  3. from表单文件上传后页面跳转解决办法

    from表单上传文件,路径跳转后,又不能转发回来. 本人的一个解决办法是.返回一段html代码,浏览器解析后后退一步,回到原来的页面并刷新. return "<html>< ...

  4. 【CF522A】Reposts

    题目大意:给定一个有向图,求图中最长路. 题解:直接拓扑排序后按照拓扑序枚举即可.处理时应将字符串通过 map 映射成一个点,同时注意字符串大小写转换,C++ string 中没有提供直接大小写转换的 ...

  5. 《剑指offer》— JavaScript(25)复杂链表的复制

    复杂链表的复制 题目描述 输入一个复杂链表(每个节点中有节点值,以及两个指针,一个指向下一个节点,另一个特殊指针指向任意一个节点),返回结果为复制后复杂链表的head.(注意,输出结果中请不要返回参数 ...

  6. P3861 8月月赛A

    https://www.luogu.org/problemnew/show/P3861 排序:乘数保持单调递增 dp+hash(map解决) #include <cstdio> #incl ...

  7. sqlserver运行脚本数据出现 内存不足的解决办法

    但是当数据库导出脚本很大,用Microsoft SQL Server Management Studio执行脚本时,往往会遇到“内存不足”的提示. 解决办法: 用微软自带的sqlcmd工具,可以导入执 ...

  8. 【Linux】MySQL安装及允许远程访问

    安装环境/工具  Linux( centOS 版) MySQL(MySQL-5.6.28-1.el7.x86_64.rpm-bundle.tar版) 安装步骤 1.解压mysql安装文件 命令:tar ...

  9. C标准库函数中复杂的函数声明

    <signal.h> 中有一个复杂的函数声明.很叫人费解. void (*signal(int sig, void (*handler)(int)))(int); 我们按照向右看向左看的黄 ...

  10. 在Windows 2008上安装Windows Mobile设备中心

    我在windows2008系统上安装Microsoft Windows Mobile Device Center v6.1时,老是弹出对话框提示缺少一个Windows Mobile设备中心所需要的Wi ...