MySQL索引优化实例说明

下面分别创建三张表,并分别插入1W条简单的数据用来测试,详情如下:

[1] test_a 有主键但无索引

CREATE TABLE `test_a` (

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

`title` varchar(100) NOT NULL,

`content` text NOT NULL,

`number` int(10) unsigned NOT NULL,

PRIMARY KEY (`id`)

) ENGINE=InnoDB AUTO_INCREMENT=0 DEFAULT CHARSET=utf8;

[2] test_b 有主键和单列索引

CREATE TABLE `test_b` (

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

`title` varchar(100) NOT NULL,

`content` text NOT NULL,

`number` int(10) unsigned NOT NULL,

PRIMARY KEY (`id`),

UNIQUE KEY `titleIndex` (`title`) USING BTREE,

UNIQUE KEY `numberIndex` (`number`) USING BTREE

) ENGINE=InnoDB AUTO_INCREMENT=0 DEFAULT CHARSET=utf8;

[3] test_c 有主键和组合索引

CREATE TABLE `test_c` (

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

`title` varchar(100) NOT NULL,

`content` text NOT NULL,

`number` int(10) unsigned NOT NULL,

PRIMARY KEY (`id`),

KEY `titleNumberIndex` (`title`,`number`) USING BTREE

) ENGINE=InnoDB AUTO_INCREMENT=0 DEFAULT CHARSET=utf8;

下面按照单列索引和组合索引分别对以上三张表进行查询测试,另外下面的时间都是多次测试取的平均值。

[1] 单列索引

[1.1] 查询指定的字段

[SQL] SELECT * FROM test_a WHERE title = ‘title_5000‘;

[USE] 12ms

[SQL] SELECT * FROM test_b WHERE title = ‘title_5000‘;

[USE] <1ms

说明:可以看到未加索引时间为12ms,加索引后小于1ms,还是相差很大的。

[SQL] SELECT * FROM test_a WHERE content = ‘content_5000‘;

[USE] 13ms

[SQL] SELECT * FROM test_b WHERE content = ‘content_5000‘;

[USE] 13ms

说明:由于content字段都未加索引,因此时间基本一致。

[1.2] 测试LIKE查询

[SQL] SELECT * FROM test_a WHERE title LIKE ‘%5000‘;

[USE] 13ms

[SQL] SELECT * FROM test_b WHERE title LIKE ‘%5000‘;

[USE] 13ms

说明:两者用时基本一致,因此索引并未命中。

[SQL] SELECT * FROM test_a WHERE title LIKE ‘5000%‘;

[USE] 12ms

[SQL] SELECT * FROM test_b WHERE title LIKE ‘5000%‘;

[USE] <1ms

说明:如果LIKE是前缀匹配则会命中索引,否则不会命中。另外以上的查询结果为空,但是不影响说明索引的作用。

[1.3] 测试OR语句

[SQL] SELECT * FROM test_a WHERE title = ‘title_5000‘ OR content = ‘content_5000‘;

[USE] 13ms

[SQL] SELECT * FROM test_b WHERE title = ‘title_5000‘ OR content = ‘content_5000‘;

[USE] 13ms

说明:两者用时基本一致,因此索引并未命中。

[SQL] SELECT * FROM test_a WHERE title = ‘title_5000‘ OR number = ‘5000‘;

[USE] 13ms

[SQL] SELECT * FROM test_b WHERE title = ‘title_5000‘ OR number = ‘5000‘;

[USE] <1ms

说明:如果OR两边的字段都加索引则命中,否则只有一个加索引则不命中。

[1.4] 测试IN语句

[SQL] SELECT * FROM test_a WHERE title IN(‘title_4999‘,‘title_5000‘,‘title_5001‘);

[USE] 12ms

[SQL] SELECT * FROM test_b WHERE title IN(‘title_4999‘,‘title_5000‘,‘title_5001‘);

[USE] <1ms

说明:IN语句也是可以命中索引的。

[1.5] 测试(BETWEEN,>,>=,<,<=)语句

[SQL] SELECT * FROM test_a WHERE number <= 5000;

[USE] 14ms

[SQL] SELECT * FROM test_b WHERE number <= 5000;

[USE] 14ms

[SQL] SELECT * FROM test_a WHERE number < 5000;

[USE] 14ms

[SQL] SELECT * FROM test_b WHERE number < 5000;

[USE] 14ms

[SQL] SELECT * FROM test_a WHERE number > 5000;

[USE] 14ms

[SQL] SELECT * FROM test_b WHERE number > 5000;

[USE] 14ms

[SQL] SELECT * FROM test_a WHERE number >= 5000;

[USE] 14ms

[SQL] SELECT * FROM test_b WHERE number >= 5000;

[USE] 14ms

[SQL] SELECT * FROM test_b FORCE INDEX(numberIndex) WHERE number >= 5000;

[USE] 14ms

[SQL] SELECT * FROM test_a WHERE number BETWEEN 4999 AND 5001;

[USE] 11ms

[SQL] SELECT * FROM test_b WHERE number BETWEEN 4999 AND 5001;

[USE] <1ms

说明:BETWEEN可以命中索引,其他比较符号未命中索引,强制使用索引效果也不明显,这个应该是与MySQL的索引足够性判断,如果索引大于30%就会使用全表扫描,具体待我查证后再详细介绍。

[1.6] 字段使用函数

[SQL] SELECT * FROM test_a WHERE SUBSTR(title,7,4) = ‘5000‘;

[USE] 13ms

[SQL] SELECT * FROM test_b WHERE SUBSTR(title,7,4) = ‘5000‘;

[USE] 13ms

说明:对字段使用函数则不能命中索引。

[2] 组合索引

[2.1] 测试OR语句

[SQL] SELECT * FROM test_a WHERE title = ‘title_5000‘ OR content = ‘content_5000‘;

[USE] 13ms

[SQL] SELECT * FROM test_c WHERE title = ‘title_5000‘ OR content = ‘content_5000‘;

[USE] 13ms

说明:组合索引中的OR语句没有命中索引。

[2.2] 测试AND语句

[SQL] SELECT * FROM test_a WHERE title = ‘title_5000‘ AND number = 5000;

[USE] 12ms

[SQL] SELECT * FROM test_c WHERE title = ‘title_5000‘ AND number = 5000;

[USE] <1ms

[SQL] SELECT * FROM test_a WHERE number = 5000;

[USE] 12ms

[SQL] SELECT * FROM test_c WHERE number = 5000;

[USE] 12ms

[SQL] SELECT * FROM test_a WHERE title = ‘title_5000‘;

[USE] 12ms

[SQL] SELECT * FROM test_c WHERE title = ‘title_5000‘;

[USE] <1ms

说明:以上证明了最左前缀匹配原则。

MySQL中EXPLAIN解释命令

EXPLAIN命令显示了mysql如何使用索引来处理select语句以及连接表。可以帮助选择更好的索引和写出更优化的查询语句。

使用方法,在select语句前加上explain就可以了,如:

1

explain select surname,first_name form a,b where a.id=b.id

EXPLAIN列的解释:

table:显示这一行的数据是关于哪张表的

type:这是重要的列,显示连接使用了何种类型。从最好到最差的连接类型为const、eq_reg、ref、range、indexhe和ALL

possible_keys:显示可能应用在这张表中的索引。如果为空,没有可能的索引。可以为相关的域从WHERE语句中选择一个合适的语句

key:实际使用的索引。如果为NULL,则没有使用索引。很少的情况下,MYSQL会选择优化不足的索引。这种情况下,可以在SELECT语句中使用USE INDEX(indexname)来强制使用一个索引或者用IGNORE INDEX(indexname)来强制MYSQL忽略索引

key_len:使用的索引的长度。在不损失精确性的情况下,长度越短越好

ref:显示索引的哪一列被使用了,如果可能的话,是一个常数

rows:MYSQL认为必须检查的用来返回请求数据的行数

Extra:关于MYSQL如何解析查询的额外信息。将在表4.3中讨论,但这里可以看到的坏的例子是Using temporary和Using filesort,意思MYSQL根本不能使用索引,结果是检索会很慢

extra列返回的描述的意义

Distinct:一旦MYSQL找到了与行相联合匹配的行,就不再搜索了

Not exists: MYSQL优化了LEFT JOIN,一旦它找到了匹配LEFT JOIN标准的行,就不再搜索了

Range checked for each Record(index map:#):没有找到理想的索引,因此对于从前面表中来的每一个行组合,MYSQL检查使用哪个索引,并用它来从表中返回行。这是使用索引的最慢的连接之一

Using filesort: 看到这个的时候,查询就需要优化了。MYSQL需要进行额外的步骤来发现如何对返回的行排序。它根据连接类型以及存储排序键值和匹配条件的全部行的行指针来排序全部行

Using index: 列数据是从仅仅使用了索引中的信息而没有读取实际的行动的表返回的,这发生在对表的全部的请求列都是同一个索引的部分的时候

Using temporary 看到这个的时候,查询需要优化了。这里,MYSQL需要创建一个临时表来存储结果,这通常发生在对不同的列集进行ORDER BY上,而不是GROUP BY上

Where used 使用了WHERE从句来限制哪些行将与下一张表匹配或者是返回给用户。如果不想返回表中的全部行,并且连接类型ALL或index,这就会发生,或者是查询有问题不同连接类型的解释(按照效率高低的顺序排序)

system 表只有一行:system表。这是const连接类型的特殊情况

const:表中的一个记录的最大值能够匹配这个查询(索引可以是主键或惟一索引)。因为只有一行,这个值实际就是常数,因为MYSQL先读这个值然后把它当做常数来对待

eq_ref:在连接中,MYSQL在查询时,从前面的表中,对每一个记录的联合都从表中读取一个记录,它在查询使用了索引为主键或惟一键的全部时使用

ref:这个连接类型只有在查询使用了不是惟一或主键的键或者是这些类型的部分(比如,利用最左边前缀)时发生。对于之前的表的每一个行联合,全部记录都将从表中读出。这个类型严重依赖于根据索引匹配的记录多少—越少越好

range:这个连接类型使用索引返回一个范围中的行,比如使用>或<查找东西时发生的情况

index: 这个连接类型对前面的表中的每一个记录联合进行完全扫描(比ALL更好,因为索引一般小于表数据)

ALL:这个连接类型对于前面的每一个记录联合进行完全扫描,这一般比较糟糕,应该尽量避免

时间: 2024-10-07 06:30:19

MySQL索引优化实例说明的相关文章

mysql索引优化

mysql 索引优化 >mysql一次查询只能使用一个索引.如果要对多个字段使用索引,建立复合索引. >越小的数据类型通常更好:越小的数据类型通常在磁盘.内存和CPU缓存中都需要更少的空间,处理起来更快. >简单的数据类型更好:整型数据比起字符,处理开销更小,因为字符串的比较更复杂.在MySQL中,应该用内置的日期和时间数据类型,而不是用字符串来存储时间:以及用整型数据类型存储IP地址. >尽量避免NULL:应该指定列为NOT NULL,除非你想存储NULL.在MySQL中,含有空

MySQL索引优化-from 高性能MYSQL

Btree: 1. 尽量使用覆盖索引, 即三星索引 2. 多列索引如果带范围的话, 后续列不会作为筛选条件 3. 多列索引应选择过滤性更好的充当前缀索引 4. 尽量按主键顺序插入, 减少页分裂, 采用自增ID在高并发情况下, 可能造成明显征用, 或者更改innodb_autoinc_lock_mode配置. Hash: 1.只有精确匹配所有列的查询才有效, 对于每行数据, 引擎都会对所有索引列计算hash码 2. 只有memory才可以支持hash索引, innodb支持自适应hash索引, 但

【转载】MySQL索引优化

MySQL索引优化 原文链接 MySQL官方对索引的定义:索引是帮助MySQL高效获取数据的数据结构.索引是在存储引擎中实现的,所以每种存储引擎中的索引都不一样.如MYISAM和InnoDB存储引擎只支持BTree索引:MEMORY和HEAP储存引擎可以支持HASH和BTREE索引. 这里仅针对常用的InnoDB存储引擎所支持的BTree索引进行介绍: 一.索引类型 先创建一个新表,用于演示索引类型 CREATE TABLE index_table ( id BIGINT NOT NULL au

Mysql 索引优化分析

MySQL索引优化分析 为什么你写的sql查询慢?为什么你建的索引常失效?通过本章内容,你将学会MySQL性能下降的原因,索引的简介,索引创建的原则,explain命令的使用,以及explain输出字段的意义.助你了解索引,分析索引,使用索引,从而写出更高性能的sql语句.还在等啥子?撸起袖子就是干! 案例分析 我们先简单了解一下非关系型数据库和关系型数据库的区别. MongoDB是NoSQL中的一种.NoSQL的全称是Not only SQL,非关系型数据库.它的特点是性能高,扩张性强,模式灵

mySql索引优化分析

MySQL索引优化分析 为什么你写的sql查询慢?为什么你建的索引常失效?通过本章内容,你将学会MySQL性能下降的原因,索引的简介,索引创建的原则,explain命令的使用,以及explain输出字段的意义.助你了解索引,分析索引,使用索引,从而写出更高性能的sql语句.还在等啥子?撸起袖子就是干! 案例分析 我们先简单了解一下非关系型数据库和关系型数据库的区别.MongoDB是NoSQL中的一种.NoSQL的全称是Not only SQL,非关系型数据库.它的特点是性能高,扩张性强,模式灵活

MySQL索引优化步骤总结

在项目使用mysql过程中,随着系统的运行,发现一些慢查询,在这里总结一下mysql索引优化步骤 1.开发过程优化 开发过程中对业务表中查询sql分析sql执行计划(尤其是业务流水表),主要是查看sql执行计划,对sql进行优化. explain执行计划关键属性 select_type,possible_keys,key,rows (1) select_type 访问类型 system>const > eq_ref > ref > fulltext > ref_or_null

数据库优化(二)—— MySQL索引优化

目录 MySQL的索引优化 一.MySQL 5.7的初始化配置 二.MySQL配置文件 1.配置 2.配置文件作用 三.多实例 1.创建相关的目录 2.创建实例的配置文件 3.初始化 4.授权 5.启动实例 6.查看启动状况 7.测试 8.配置启动脚本 9.开机自启 10.设定mysql密码 11.忘记密码 四.数据类型 1.整型 2.字符串类型 3.时间类型 规范 五.索引 1.索引作用 2.索引种类 3.Btree 分类 4.聚集索引和辅助索引的对比 六.MySQL索引管理 1.创建索引(辅

MySQL 索引优化原则

一.索引优化原则 1.最左前缀匹配原则,联合索引,mysql会从做向右匹配直到遇到范围查询(>.<.between.like)就停止匹配,比如a = 1 and b = 2 and c > 3 and d = 4 如果建立(a,b,c,d)顺序的索引,d是用不到索引的,如果建立(a,b,d,c)的索引则都可以用到,a,b,d的顺序可以任意调整. 2.=和in可以乱序,比如a = 1 and b = 2 and c = 3 建立(a,b,c)索引可以任意顺序,mysql的查询优化器会帮你优

Mysql 索引优化

索引的存储分类MyISAM 存储引擎的表数据和索引是自动分开存储的,各自是独一的一个文件Innodb 存储引擎的表数据和索引是存储在同一个表空间里面,但可以由多个文件构成.Mysql 目前不支持函数索引,但是能对列的前面某一部分进行索引例如 name 字段,可以只取 name 的前 4 个字符进行索引,可降低索引文件大小.Mysql> create index ind_company_name on company(name(4));说明:ind_company_name 索引名,company