热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

mysql内连接使用联合索引顺序_MySQL联合索引是否支持不同排序规则

篇首语:截止到目前的5.7.4版本为止,MySQL的联合索引仍无法支持联合索引使用不同排序规则,例如:ALTERTABLEt

篇首语:

截止到目前的5.7.4版本为止,MySQL的联合索引仍无法支持联合索引使用不同排序规则,例如:ALTER TABLE t ADD INDEX idx(col1, col2 DESC)。

先来了解下MySQL关于索引的一些基础知识要点:

• a、EXPLAIN结果中的key_len只显示了条件检索子句需要的索引长度,但 ORDER BY、GROUP BY 子句用到的索引则不计入 key_len 统计值;

• b、联合索引(composite index):多个字段组成的索引,称为联合索引;

例如:ALTER TABLE t ADD INDEX `idx` (col1, col2, col3)

• c、覆盖索引(covering index):如果查询需要读取到索引中的一个或多个字段,则可以从索引树中直接取得结果集,称为覆盖索引;

例如:SELECT col1, col2 FROM t;

• d、最左原则(prefix index):如果查询条件检索时,只需要匹配联合索引中的最左顺序一个或多个字段,称为最左索引原则,或者叫最左前缀;

例如:SELECT * FROM t WHERE col1 = ? AND col2 = ?;

• e、在老版本(大概是5.5以前,具体版本号未确认核实)中,查询使用联合索引时,可以不区分条件中的字段顺序,在这以前是需要按照联合索引的创建顺序书写SQL条件子句的;

例如:SELECT * FROM t WHERE col3 = ? AND col1 = ? AND col2 = ?;

• f、MySQL截止目前还只支持多个字段都是正序索引,不支个别字段持倒序索引;

例如:ALTER TABLE t ADD INDEX `idx` (col1, col2, col3 DESC),这里的DESC只是个预留的关键字,目前还不能真正有作用

• g、联合索引中,如果查询条件中最左边某个索引列使用范围查找,则只能使用前缀索引,无法使用到整个索引;

例如:SELECT * FROM t WHERE col1 = ? AND col2 >= ? AND col3 = ?; 这时候,只能用到 idx 索引的最左2列进行检索,而col3条件则无法利用索引进行检索

• h、InnoDB引擎中,二级索引实际上包含了主键索引值;

关于 key_len 的计算规则:

• 当索引字段为定长数据类型,比如:char,int,datetime,需要有是否为空的标记,这个标记需要占用1个字节;

• 当索引字段为变长数据类型,比如:varchar,除了是否为空的标记外,还需要有长度信息,需要占用2个字节;

• 当字段定义为非空的时候,是否为空的标记将不占用字节;

• 同时还需要考虑表所使用字符集的差异,latin1编码一个字符1个字节,gbk编码一个字符2个字节,utf8编码一个字符3个字节;

因此,key_len长度的计算公式

• varchr(10)变长字段且允许NULL : 10*(Character Set:utf8=3,gbk=2,latin1=1)+1(NULL标记位)+2(变长字段)

• varchr(10)变长字段且不允许NULL : 10*(Character Set:utf8=3,gbk=2,latin1=1)+2(变长字段)

• char(10)固定字段且允许NULL : 10*(Character Set:utf8=3,gbk=2,latin1=1)+1(NULL标记位)

• char(10)固定字段且不允许NULL : 10*(Character Set:utf8=3,gbk=2,latin1=1)

附,关于 filesort 排序算法:

光看 filesort 字面意思,可能以为是要利用磁盘文件进行排序,实则不全然。

当MySQL不能使用索引进行排序时,就会利用自己的排序算法(快速排序算法)在内存(sort buffer)中对数据进行排序,如果内存装载不下,它会将磁盘上的数据进行分块,再对各个数据块进行排序,然后将各个块合并成有序的结果集(实际上就是外排序)。

对于filesort,MySQL有两种排序算法:

1、两遍扫描算法(Two passes)

实现方式是先将须要排序的字段和可以直接定位到相关行数据的指针信息取出,然后在设定的内存(通过参数 sort_buffer_size 设定)中进行排序,完成排序之后再次通过行指针信息取出所需的列。

注:该算法是4.1之前只有这种算法,它需要两次访问数据,尤其是第二次读取操作会导致大量的随机I/O操作。不过,这种方法内存开销较小。

2、一次扫描算法(single pass)

该算法一次性将所需的列全部取出,在内存中排序后直接将结果输出。

注:从 MySQL 4.1 版本开始支持该算法。它减少了I/O的次数,效率较高,但是内存开销也较大。如果我们将并不需要的列也取出来,就会极大地浪费排序过程所需要的内存。在 MySQL 4.1 之后的版本中,可以通过设置 max_length_for_sort_data 参数来控制 MySQL 选择第一种排序算法还是第二种。当取出的所有大字段总大小大于max_length_for_sort_data 的设置时,MySQL 就会选择使用第一种排序算法,反之,则会选择第二种。为了尽可能地提高排序性能,我们自然更希望使用第二种排序算法,所以在SQL中仅仅取出需要的列是非常有必要的。

当对连接操作进行排序时,如果ORDER BY仅仅引用第一个表的列,MySQL对该表进行filesort操作,然后进行连接处理,此时,EXPLAIN输出“Using filesort”;否则,MySQL必须将查询的结果集生成一个临时表,在连接完成之后进行filesort操作,此时,EXPLAIN输出“Using temporary;Using filesort”。

后面是几个几个测试结果,有兴趣不怕累的可以看看,哈哈。

测试MySQL版本:5.5.37-log MySQL Community Server (GPL)

创建一个测试表,id是主键字段,(a1, a2) 组成联合索引

(yejr@imysql.com)> show create table t\G

*************************** 1\. row ***************************

Table: t

Create Table: CREATE TABLE `t` (

`id` int(10) unsigned NOT NULL AUTO_INCREMENT,

`a1` int(10) unsigned NOT NULL DEFAULT '0',

`a2` int(10) unsigned NOT NULL DEFAULT '0',

`aa` varchar(20) NOT NULL DEFAULT '',

PRIMARY KEY (`id`),

KEY `idx` (`a1`,`a2`)

) ENGINE=InnoDB AUTO_INCREMENT=65 DEFAULT CHARSET=utf8

填充了64条测试数据

(yejr@imysql.com)> show table status like 't'\G

*************************** 1\. row ***************************

Name: t

Engine: InnoDB

Version: 10

Row_format: Compact

Rows: 64

Avg_row_length: 256

Data_length: 16384

Max_data_length: 0

Index_length: 16384

Data_free: 0

Auto_increment: 122

Create_time: 2014-09-15 17:17:09

Update_time: NULL

Check_time: NULL

Collation: utf8_general_ci

Checksum: NULL

Create_options:

Comment:

对 a1、a2 正序排序,同时取a1、a2两个字段,可以直接使用该联合索引取回结果,并且排序完成

符合规则c

(yejr@imysql.com)> explain select a1, a2 from t order by a1, a2\G

id: 1

select_type: SIMPLE

table: t

type: index

possible_keys: NULL

key: idx

key_len: 8

ref: NULL

rows: 64

Extra: Using index

对 a1、a2 倒序排序,同时取a1、a2两个字段,可以直接使用该联合索引取回结果,并且排序完成

由于同时对a1、a2都是倒序排序,因此完全可以用到索引的顺序,只是反向扫描而已

符合规则c

(yejr@imysql.com)> explain select a1, a2 from t order by a1 desc, a2 desc\G

*************************** 1\. row ***************************

id: 1

select_type: SIMPLE

table: t

type: index

possible_keys: NULL

key: idx

key_len: 8

ref: NULL

rows: 64

Extra: Using index

对 a1、a2正序排序,只取a1字段,可以直接使用该联合索引取回结果,并且排序完成

匹配规则c

(yejr@imysql.com)> explain select a1 from t order by a1, a2\G

id: 1

select_type: SIMPLE

table: t

type: index

possible_keys: NULL

key: idx

key_len: 8

ref: NULL

rows: 64

Extra: Using index

对 a1、a2 正序排序,只取a2字段,可以直接使用该联合索引取回结果,并且排序完成

符合规则c

(yejr@imysql.com)> explain select a2 from t order by a1, a2 \G

id: 1

select_type: SIMPLE

table: t

type: index

possible_keys: NULL

key: idx

key_len: 8

ref: NULL

rows: 64

Extra: Using index

只对 a1 正序排序,同时取a1、a2两个字段,可以直接使用该联合索引取回结果,并且排序完成

符合规则c

(yejr@imysql.com)> explain select a1, a2 from t order by a1\G

id: 1

select_type: SIMPLE

table: t

type: index

possible_keys: NULL

key: idx

key_len: 8

ref: NULL

rows: 64

Extra: Using index

对 a1 正序排序,对 a2 倒序排序,只取a1字段,可以直接使用该联合索引取回结果,但排序时需要进行filesort排序,不能利用索引直接得到排序结果

这时虽然只读取一个字段,但实际还是扫描了整个索引,并非使用前缀索引

符合规则c、f

(yejr@imysql.com)> explain select a1 from t order by a1, a2 desc \G

id: 1

select_type: SIMPLE

table: t

type: index

possible_keys: NULL

key: idx

key_len: 8

ref: NULL

rows: 64

Extra: Using index; Using filesort

只取a1字段,同时只对 a1 字段正序排序,这时可用联合索引取得结果,同时也可以利用前缀索引的原则进行排序

符合规则c

(yejr@imysql.com)> explain select a1 from t order by a1\G

id: 1

select_type: SIMPLE

table: t

type: index

possible_keys: NULL

key: idx

key_len: 8

ref: NULL

rows: 64

Extra: Using index

只取a1字段,同时只对 a2 字段正序排序,这时虽然可用联合索引取得结果,但排序时需要进行filesort排序,不能利用索引直接得到排序结果

符合规则c、f

(yejr@imysql.com)> explain select a1 from t order by a2\G

id: 1

select_type: SIMPLE

table: t

type: index

possible_keys: NULL

key: idx

key_len: 8

ref: NULL

rows: 64

Extra: Using index; Using filesort

对 a1 正序排序,对a2 倒序排序,只取a1字段,可以直接使用该联合索引取回结果,但排序时需要进行filesort排序,不能利用索引直接得到排序结果

这时虽然只读取一个字段,但实际还是扫描了整个索引,并非使用前缀索引

符合规则c、f

(yejr@imysql.com)> explain select a1 from t order by a1, a2 desc \G

id: 1

select_type: SIMPLE

table: t

type: index

possible_keys: NULL

key: idx

key_len: 8

ref: NULL

rows: 64

Extra: Using index; Using filesort

对 a1 正序排序,对a2 倒序排序,只取a2字段,可以直接使用该联合索引取回结果,但排序时需要进行filesort排序,不能利用索引直接得到排序结果

这时虽然只读取一个字段,但实际还是扫描了整个索引,并非使用前缀索引

符合规则c、f

(yejr@imysql.com)> explain select a2 from t order by a1, a2 desc \G

id: 1

select_type: SIMPLE

table: t

type: index

possible_keys: NULL

key: idx

key_len: 8

ref: NULL

rows: 64

Extra: Using index; Using filesort

对 a1 正序排序,对a2 倒序排序,只取a2字段,可以直接使用该联合索引取回结果,但排序时需要进行filesort排序,不能利用索引直接得到排序结果

这时虽然只读取一个字段,但实际还是扫描了整个索引,并非使用前缀索引

符合规则c、f

(yejr@imysql.com)> explain select a1 from t order by a1, a2 \G

id: 1

select_type: SIMPLE

table: t

type: index

possible_keys: NULL

key: idx

key_len: 8

ref: NULL

rows: 64

Extra: Using index

对 a1 、a2顺序排序,取得主键id字段,可以直接使用该联合索引取回结果并完成排序。

这里需要注意下,二级索引其实是包括主键索引的,因此用idx索引即可取到全部结果。

下面这个SQL也是一样的效果:select a1,a2,id from t order by a1, a2;

符合规则c、h

(yejr@imysql.com)> explain select id from t order by a1, a2 \G

id: 1

select_type: SIMPLE

table: t

type: index

possible_keys: NULL

key: idx

key_len: 8

ref: NULL

rows: 64

Extra: Using index

对 a1 正序排序,对a2 倒序排序,取得主键id字段,可以直接使用该联合索引取回结果,但需要进行filesort排序。

符合规则c、f、h

(yejr@imysql.com)> explain select id from t order by a1, a2 desc \G

id: 1

select_type: SIMPLE

table: t

type: index

possible_keys: NULL

key: idx

key_len: 8

ref: NULL

rows: 64

Extra: Using index; Using filesort

对 a1 倒序排序,对a2 正序排序,取得主键id字段,可以直接使用该联合索引取回结果,但需要进行filesort排序。

符合规则c、f、h

(yejr@imysql.com)> explain select id from t order by a1 desc, a2 \G

id: 1

select_type: SIMPLE

table: t

type: index

possible_keys: NULL

key: idx

key_len: 8

ref: NULL

rows: 64

Extra: Using index; Using filesort

过滤条件a1字段(使用前缀索引扫描,key_len为4),对a2字段进行正序排序,取得主键id字段,可以直接使用联合索引取回结果

符合规则a、c、d、h

(yejr@imysql.com)> explain select id from t where a1 = 219 order by a2\G

id: 1

select_type: SIMPLE

table: t

type: ref

possible_keys: idx

key: idx

key_len: 4

ref: const

rows: 2

Extra: Using where; Using index



推荐阅读
  • 二维码的实现与应用
    本文介绍了二维码的基本概念、分类及其优缺点,并详细描述了如何使用Java编程语言结合第三方库(如ZXing和qrcode.jar)来实现二维码的生成与解析。 ... [详细]
  • 如何将955万数据表的17秒SQL查询优化至300毫秒
    本文详细介绍了通过优化SQL查询策略,成功将一张包含955万条记录的财务流水表的查询时间从17秒缩短至300毫秒的方法。文章不仅提供了具体的SQL优化技巧,还深入探讨了背后的数据库原理。 ... [详细]
  • 本文探讨了如何在PHP与MySQL环境中实现高效的分页查询,包括基本的分页实现、性能优化技巧以及高级的分页策略。 ... [详细]
  • Maven + Spring + MyBatis + MySQL 环境搭建与实例解析
    本文详细介绍如何使用MySQL数据库进行环境搭建,包括创建数据库表并插入示例数据。随后,逐步指导如何配置Maven项目,整合Spring框架与MyBatis,实现高效的数据访问。 ... [详细]
  • 在1995年,Simon Plouffe 发现了一种特殊的求和方法来表示某些常数。两年后,Bailey 和 Borwein 在他们的论文中发表了这一发现,这种方法被命名为 Bailey-Borwein-Plouffe (BBP) 公式。该问题要求计算圆周率 π 的第 n 个十六进制数字。 ... [详细]
  • 本文详细介绍了PostgreSQL与MySQL在SQL语法上的主要区别,包括如何使用COALESCE替代IFNULL、金额格式化的方法、别名处理以及日期处理等关键点。 ... [详细]
  • 本文详细介绍了在Linux操作系统上安装和部署MySQL数据库的过程,包括必要的环境准备、安装步骤、配置优化及安全设置等内容。 ... [详细]
  • HTML:  将文件拖拽到此区域 ... [详细]
  • flea,frame,db,使用,之 ... [详细]
  • 本文详细探讨了在Java中如何将图像对象转换为文件和字节数组(Byte[])的技术。虽然网络上存在大量相关资料,但实际操作时仍需注意细节。本文通过使用JMSL 4.0库中的图表对象作为示例,提供了一种实用的方法。 ... [详细]
  • 处理Android EditText中数字输入与parseInt方法
    本文探讨了如何在Android应用中从EditText组件安全地获取并解析用户输入的数字,特别是用于设置端口号的情况。通过示例代码和异常处理策略,展示了有效的方法来避免因非法输入导致的应用崩溃。 ... [详细]
  • Irish budget airline Ryanair announced plans to significantly increase its route network from Frankfurt Airport, marking a direct challenge to Lufthansa, Germany's leading carrier. ... [详细]
  • 本文探讨了在SQL Server中处理几何类型列时遇到的INTERSECT操作限制,并提供了解决方案,包括通过转换数据类型和使用额外表结构的方法。 ... [详细]
  • 本文记录了在Windows 8.1系统环境下,使用IIS 8.5和Visual Studio 2013部署Orchard 1.7.2过程中遇到的问题及解决方案,包括503服务不可用错误和web.config配置错误。 ... [详细]
  • 流处理中的计数挑战与解决方案
    本文探讨了在流处理中进行计数的各种技术和挑战,并基于作者在2016年圣何塞举行的Hadoop World大会上的演讲进行了深入分析。文章不仅介绍了传统批处理和Lambda架构的局限性,还详细探讨了流处理架构的优势及其在现代大数据应用中的重要作用。 ... [详细]
author-avatar
谢俊荣1792
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有