索引(index)是帮助MySQL高效获取数据的数据结构, 在数据之外, 数据库系统还维护着满足特定查找算法的数据结构, 这些数据结构以某种方式引用(指向)数据, 这样就可以在这些数据结构上实现高级查找算法, 这种数据结构就是索引
如果表中某个字段没有索引, 那么以该字段进行查找的时候就要进行一个全表扫描, 效率是非常低的
如果表中某个字段是有索引, 那么通过索引这个数据结构, 我们查找的效率就会非常高
数据库在存储数据本身之外, 还维护着一个满足特定查找算法的数据结构, 这些数据结构以某种方式指向数据, 这样就可以在这些数据结构的基础上实现高级查找算法, 这种数据结构就是索引
优势 | 劣势 |
---|---|
提高数据检索的效率, 降低数据库的IO成本 | 索引列也是要占用空间的 |
通过索引列队数据进行排序, 降低数据排序的成本, 降低cpu的消耗 | 索引大大提高了查询效率, 但是同时也降低了更新表的速度, 如对表进行insert, update, delete时效率降低 |
MySQL的索引是在存储引擎层实现的, 不同的存储引擎有不同的结构, 主要包含以下几种:
索引结构 | 描述 |
---|---|
B+Tree索引 | 最常见的索引, 大部分的存储引擎都支持B+树索引 (InnoDB, MyISAM, Memory都支持B+树索引) |
Hash索引 | 底层数据结构是用哈希表实现的, 只有精确匹配索引列的查询才有效, 不支持范围查询 |
R-Tree(空间索引) | 空间索引是MyISAM引擎的一个特殊索引类型, 主要用于地理空间数据类型, 通常使用较少 |
Full-Text(全文索引) | 是一种通过建立倒排索引, 快速匹配文档的方式, 类似于Lucene, Solr, ES |
InnoDB存储引擎1的默认索引结构就是B+Tree索引
索引 | InnoDB | MyISAM | Memory |
---|---|---|---|
B+Tree索引 | 支持 | 支持 | 支持 |
Hash索引 | 不支持 | 不支持 | 支持 |
R-Tree索引(空间索引) | 不支持 | 支持 | 不支持 |
Full-Text索引(全文索引) | 5.6之后支持 | 支持 | 不支持 |
这个是一个传统的B+树, 是没有经过改变的, MySQL中的B+Tree索引结构并不是这样的, 而是将叶子结点的结构从单向链表修改成为了双向链表
有的同学觉得这不是一个B+树, 这其实是因为B+树是有两种的:
要知道B+树中数据都是存储在叶子结点的, 非叶子结点的作用就是一个索引的结构, 只要能找到叶子结点就可以了
B+树的叶子节点是以单向链表, 这样是利于排序的
hash索引结构其实是和Java中的HashMap很像的, jdk7之前的时候HashMap就是数组 + 链表, 也就是使用的链表解决的hash冲突, MySQL中的hash索引也是使用的链表解决的hash冲突
在MySQL中, 支持hash索引的是Memory引擎, 而InnoDB中具有自适应hash功能, hash索引是存储引擎根据B+Tree索引在指定条件下自动构建的
分类 | 含义 | 特点 | 关键字 |
---|---|---|---|
主键索引 | 针对于表中主键创建的索引 | 默认自动创建, 只能有一个 | PRIMARY |
唯一索引 | 避免同一个表中某数据列中的值重复 | 可以有多个 | UNIQUE |
常规索引 | 快读定位特定数据 | 可以有多个 | |
全文索引 | 全文索引查找的是文本中的关键词, 而不是比较索引中的值 | 可以有多个 | FULLTEXT |
分类 | 含义 | 特点 |
---|---|---|
聚集索引(Clustered Index) | 将数据存储与索引放到了一块, 索引结构的叶子结点保存了行数据 | 必须有, 而且只有一个 |
二级索引(Secondary Index) | 将数据与索引分开存储, 索引结构的叶子结点关联的是对应的主键 | 可以存在多个 |
select * from user where id = 10;
select * from user where name = "Arm";
解答 : 第一条语句执行的效率高, 第二条比较慢, 因为第二条sql需要进行回表查询
解答 : 假设一行数据大小为1k, 一页中就可以存储16行这样的数据. InnoDB的指针占用6个字节的空间, 主键即使为bigint, 占用字节数目为8(如果是int, 占用字节数为4)
n * 8 + (n + 1) * 6 = 16 * 1024, 算出n约为1170
那么如果高度为2 : 1171 * 16 = 18736
如果高度为3 : 1171 * 1171 * 16 = 21939856
CREATE [UNIQUE | FULLTEXT] INDEX index_name on table_name(index_col_name, ...);
SHOW INDEX FROM table_name;
DROP INDEX index_name ON table_name;
MySQL客户端连接成功后, 通过show [session | global] status命令可以提供服务器状态信息, 通过如下指令, 可以查看当前数据库INSERT, UPDATE, DELETE, SELECT的访问频次
SHOW GLOBAL STATUS LIKE 'Com_______(这里一共是七个下划线)'
慢查询日志记录了所有执行时间超过指定参数(long_query_time, 单位 : 秒, 默认10秒)的所有SQL语句的日志
MySQL的慢查询日志默认没有开启, 需要在MySQL的配置文件(/etc/my.cnf) [linux]中配置如下信息:
开启MySQL慢日志查询开关
slow_query_log=1
设置慢日志的时间为2秒, SQL语句执行时间超过2秒, 就会被视为慢查询, 记录到慢查询日志当中
long_query_time=2
慢日志文件保存为/var/lib/mysql/localhost-slow.log
执行一系列的业务SQL的操作, 然后通过如下指令查看指令的执行耗时
show profiles;
show profile for query query_id;
explain执行计划各个字段的含义:
id :
select 查询的序列号, 表示查询中执行select子句(或者是操作表)的顺序(id相同, 执行顺序从上到下, id不同, 值越大, 越先执行)
select_type:
表示select的类型, 常见的取值有SIMPLE(简单表, 即不使用表连接或者是子查询), PRIMARY(主查询, 即外层的查询), UNION(UNION中第二个或者后面的查询语句), SUBQUERY(select/where之后包含了子查询)等
type:
表示连接类型, 性能好到差的连接类型为NULL, system, const, eqref, ref, range, index, all
我们在业务中尽量往前优化即可
possible_key:
显示可能使用在这张表上的索引, 一个或者多个 (如果有多个就会显示多个)
key:
实际使用到的索引, 如果为NULL, 则表示没有使用到索引
key_len
表示索引中使用的字节数, 该值为索引字段的最大可能长度, 并非实际使用长度, 在不损失精度的情况之下, 长度越短越好
rows
MySQL认为必须要执行查询的行数, 在innoDB引擎的表中, 是一个预估值, 可能并不是完全准确的
filtered
表示返回结果的行数占需要读取行数的百分比,filtered值越大越好
Extra
额外信息, 前面的字段中没有展示的信息将会在extra字段中展示出来
这几个字段中我们最需要关注的有 : type, possible_key, key, key_len, Extra
如果索引了多列(联合索引), 要遵守最左前缀法则, 最左前缀法则指的是查询从索引的最左列开始, 并且不跳过索引中的列. 如果跳过了某一列, 索引将会失效(后面的字段索引失效)
联合索引中, 出现范围查询(>, <), 范围查询右侧的索引列将会失效
eg: 注意: 我们创建了联合索引(以profession, age, status三个字段创建的(上述顺序))
select * from tb_user where profession = '软件工程' and age > 30 and status = '0';
但是注意: >=和<=并不在范围查询的范围内, 所以我们可以将>和<在业务中尽量的替换为>=,<=, 由于对应列可能要创建联合索引进行查询的情况之下, 这样就不会导致索引失效问题了
select * from tb_user where profession = '软件工程' and age >= 31 and status = '0';
不要在索引列上进行运算操作, 索引将会失效
select * from tb_user where substring(phone,10,2);
字符串类型字段使用时, 不加引号, 索引将会失效
如果仅仅是尾部模糊匹配, 索引不会失效, 如果是头部模糊匹配, 索引失效
用or分割开的条件, 如果or前面的条件中的列有索引, 而后面的列中没有索引, 那么涉及的索引都不会被用到
如果MySQL评估使用索引比全表更慢, 就不会使用索引
SQL提示是优化数据库的一个重要手段, 简单来说, 就是在SQL语句中加入一些人为的提示来达到优化操作的目的