MySQL索引底层存储原理

字段类型
整型
tinyint 占用一个字节 8位 无符号最大整数 255 有符号 -128 -127
smallint 占用二个字节 16位 无符号最大整数 65535 有符号 -32768 - 32767
mediumint 占用三个字节 16位 无符号最大整数 16777215 有符号 -8388608 - 8388607
int 占用四个字节 16位 无符号最大整数 4294967295 有符号 -2147483648 - 2147483647
bigint 占用八个字节 16位 无符号最大整数 2^64-1 有符号 -2^63- 2^63

注意 tinyint(4) 括弧里面的书与实际存储大小无关 代表的是不足四位用0替补在前面 0001 用于序列号

字符串
char 定长 规定了必须存储多少字符长超出的自动截取不够的用空格补齐
varchar 边长 规定了可以在指定区间里存储字符 有多少存多少 无需补齐 超出部分会截取
0~21844

MySQL索引底层存储原理

一、二叉树


image.png

特点:左边的子元素小于父元素,右边的子元素大于父元素

缺点:当插入单边增长的数据就变成链表了不适用

二、红黑树(二叉平衡树)

image.png

特点:单左右失衡严重会自动平衡防止单边增长

缺点:层数过高即树的深度变高查找的次数就很多

三、hash

特点:每个索引做hash运算生成散列值存入hash表(散列值和索引所在行磁盘文件地址),查询元素做hash运算去hash表找到对应的元素地址

缺点:对进行范围查找时候不适用

四、B-Tree

image.png

特点:每个节点分配容量大一点(默认16kb),一个节点就可以存多个索引元素,横向就会存储多一点索引元素,数据和关键字存在同一节点

升级版 B+Tree (多叉平衡树)

image.png

非叶子节点不存储数据 只存储(索引)冗余,可以放更多索引

叶子节点包含所有索引字段

叶子节点用指针连接提高区间访问性能

对范围查找很方便

五、存储引擎

myisam (非聚集索引)每个表生成三个文件 表结构文件 frm 表数据文件 myd 表索引文件 myi 即关键字和数据不在一起 叶子节点存储的是数据指针

innodb (聚集索引) 每张表生出二个文件 表结构文件 frm 表数据和索引文件 ibd 即关键字和数据在一起 叶子节点存储的是索引和数据

聚集索引索引和数据在一起(同一个文件) 非聚集索引索引和数据不在一起(不在同一个文件)

innodb 必须有主键唯一

六、优化
1.mysql索引优化
主键索引:每张表固有的主键自动创建的索引 唯一、不能为空 primary
唯一索引:唯一且不能重复,比如在身份证号上面创建索引 unique
普通索引、复合索引:适合大部分场景 key
全文索引:mysql只支持英文全文索引 需要借助第三方实现中文全文索引
主键索引和唯一索引的区别
①主键索引是唯一约束,唯一索引是一种索引(本质区别)
②主键索引创建完成一定包含唯一索引
③一个表只能有一个主键索引
④主键索引可以被其它表引用为外键

创建普通索引

atler table emp add (drop) index(ename)

创建符合索引

alter table emp add (drop)  index `mulit_index`(ename.job,empno)

索引覆盖指的是一个索引覆盖另一个索引

索引遵循左原则 列表独立
对于复合索引同样遵循左原则指的是当左边字段生效时才会使用的索引
注意:复合索引比普通索引要好原因是当查询条件变化索引可能弃用

or的使用
必须满足or两边条件都有可用索引才能使用到索引

索引弃用
查询即使使用索引,会导致出大量的随机IO,相对于从数据记录的第一条遍历到最后一条的顺序IO开销还要大(比如性别建立索引用处不大)

2.query_cache_size 查询缓存 slow_query_log 慢查询日志

3.mysql分页优化
子查询的分页方式:
随着数据量的增加,页数会越来越多,查看后几页的SQL就可能类似:

SELECT * FROM articles WHERE category_id = 123 ORDER BY id LIMIT 10000, 10

一言以蔽之,就是越往后分页,LIMIT语句的偏移量就会越大,速度也会明显变慢。
此时,我们可以通过子查询的方式来提高分页效率,大致如下:

SELECT * FROM articles WHERE  id >=  
(SELECT id FROM articles  WHERE category_id = 123 ORDER BY id LIMIT 10000, 1) LIMIT 10 

查询是在索引上完成的,而普通的查询时在数据文件上完成的,通常来说,索引文件要比数据文件小得多,所以操作起来也会更有效率。
实际可以利用类似策略模式的方式去处理分页,比如判断如果是一百页以内,就使用最基本的分页方式,大于一百页,则使用子查询的分页方式。

4.主从复制读写分离 可能出现主从不同步附方案
先上Master库:

mysql>show processlist;   查看下进程是否Sleep太多。发现很正常。
show master status; 也正常。
mysql> show master status;
+-------------------+----------+--------------+-------------------------------+

| File              | Position | Binlog_Do_DB | Binlog_Ignore_DB              |

+-------------------+----------+--------------+-------------------------------+

| mysqld-bin.000001 |     3260 |              | mysql,test,information_schema |

+-------------------+----------+--------------+-------------------------------+

1 row in set (0.00 sec)

再到Slave上查看

mysql> show slave status\G                                                
Slave_IO_Running: Yes
Slave_SQL_Running: No

可见是Slave不同步
下面介绍两种解决方法:

方法一:忽略错误后,继续同步

该方法适用于主从库数据相差不大,或者要求数据可以不完全统一的情况,数据要求不严格的情况

解决:

stop slave;
#表示跳过一步错误,后面的数字可变
set global sql_slave_skip_counter =1;
start slave;
之后再用mysql> show slave status\G  查看:

Slave_IO_Running: Yes
Slave_SQL_Running: Yes

ok,现在主从同步状态正常了。。。

方式二:重新做主从,完全同步
该方法适用于主从库数据相差较大,或者要求数据完全统一的情况
解决步骤如下:
①.先进入主库,进行锁表,防止数据写入
使用命令:
mysql> flush tables with read lock;
注意:该处是锁定为只读状态,语句不区分大小写
②.进行数据备份

把数据备份到mysql.bak.sql文件

[root@server01 mysql]#mysqldump -uroot -p -hlocalhost > mysql.bak.sql
这里注意一点:数据库备份一定要定期进行,可以用shell脚本或者python脚本,都比较方便,确保数据万无一失
③.查看master 状态

mysql> show master status;
+-------------------+----------+--------------+-------------------------------+

| File              | Position | Binlog_Do_DB | Binlog_Ignore_DB              |

+-------------------+----------+--------------+-------------------------------+

| mysqld-bin.000001 |     3260 |              | mysql,test,information_schema |

+-------------------+----------+--------------+-------------------------------+
1 row in set (0.00 sec)

④.把mysql备份文件传到从库机器,进行数据恢复

使用scp命令

[root@server01 mysql]# scp mysql.bak.sql root@192.168.128.101:/tmp/

⑤.停止从库的状态

mysql> stop slave;

⑥.然后到从库执行mysql命令,导入数据备份
mysql> source /tmp/mysql.bak.sql

⑦.设置从库同步,注意该处的同步点,就是主库show master status信息里的| File| Position两项
change master to master_host = '192.168.128.100', master_user = 'rsync', master_port=3306, master_password='', master_log_file = 'mysqld-bin.000001', master_log_pos=3260;

⑧.重新开启从同步

mysql> start slave;

⑨.查看同步状态

mysql> show slave status\G  查看:
Slave_IO_Running: Yes
Slave_SQL_Running: Yes

好了,同步完成啦。

5.mysql水平分表垂直分表
用户表 先垂直后水平
①垂直 把复杂的用的少的字段单独放扩展表
②水平 根据垂直产生的id取模把用户数据插入对应表中
③其它业务表根据用户id可实现分表

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容