linux12 -MYSQL数据库 -->07数据库索引和存储引擎
Posted FikL-09-19
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了linux12 -MYSQL数据库 -->07数据库索引和存储引擎相关的知识,希望对你有一定的参考价值。
文章目录
一、索引
1.什么是索引
1)索引就好比一本书的目录,它能让你更快的找到自己想要的内容。
2)让获取的数据更有目的性,从而提高数据库检索数据的性能。
2.索引类型介绍
1)BTREE:B+树索引(Btree,B+tree,B*tree)
2)HASH:HASH索引 (将数据打散再去查询,Inodb和Myisam都不支持,设置完还是Btree,memery存储引擎支持)
3)FULLTEXT:全文索引 (只可以用在MyISAM引擎)
通过关键字的匹配来进行查询,类似于like的模糊匹配,like + %在文本比较少时是合适的,但是对于大量的文本数据检索会非常的慢,全文索引在大量的数据面前能比like快得多,但是准确度很低,百度在搜索文章的时候使用的就是全文索引,但更有可能是ES,
4)RTREE:R树索引
RTREE在mysql很少使用,仅支持geometry数据类型,geometry数据类型一般填写经纬度那样的数据,支持该类型的存储引擎只有MyISAM、BDb、InnoDb、NDb、Archive几种。RTREE范围查找很强,但Btree也不弱.
生活中很多算法,电梯算法,二分法
1)Btree介绍
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-eXs8zBTN-1625199271584)(C:\\Users\\12402\\AppData\\Roaming\\Typora\\typora-user-images\\1587312882355.png)]
2)B+tree
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-IzlN9HcR-1625199271588)(C:\\Users\\12402\\AppData\\Roaming\\Typora\\typora-user-images\\1587313135867.png)]
3)B*tree
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-V1qXHkSO-1625199271589)(https://www.driverzeng.com/wp-content/uploads/2018/10/15396793160450.jpg)]
3.索引根据算法分类
索引建立在表的列上(字段)的。
在where后面的列建立索引才会加快查询速度。
pages<---索引(属性)<----查数据。
1)主键索引(聚集索引)
#创建主键索引
mysql> alter table student add primary key pri_id(id);
mysql> create table student(id int not null, primary key(id));
mysql> create table student(id int not null primary key auto_increment comment '学号');
#提示:
database可以写 schema
index可以写 key
#查看索引
mysql> show index from student;
2)唯一键索引
#创建唯一建索引
mysql> alter table country add unique key uni_name(name);
mysql> create table student(id int unique key comment '学号');
mysql> create unique key index index_name on table_name(id);
扩展
#数据库修改某一列为唯一键的时候,那一列的数据不能有重复数据
#所以可以使用函数计算那一列是否有重复数据
#数据条数 类似于 wc -l
mysql> select count(name) from qiudao3;
#数据去重 类似于 uniq -c
mysql> select distinct(name) from qiudao3;
#去重之后计数,当值与没去重条数一致时可以为该列加唯一键
mysql> select count(distinct(name)) from qiudao3;
#city表name列不能做唯一键或主键
mysql> select count(name) from city;
mysql> select distinct(name) from city;
#country表name列能做唯一键或主键
mysql> select count(Name) from country;
mysql> select distinct(Name) from country;
函数总结
count() #统计
password() #加密
distinct() #去重
now() #当前时间
database() #当前数据库
max() #最大值
mysql> select max(population) from country;
min() #最小值
mysql> select min(population) from country;
sum() #求和
mysql> select sum(population) from country;
avg() #求平均值
mysql> select avg(population) from country;
3)普通索引(辅助索引)
#普通索引的创建
mysql> alter table student add index idx_gender(gender);
CREATE INDEX index_name ON table_name (column_list);
4)全文索引
#针对content做了全文索引:
CREATE TABLE pull (
id int NOT NULL AUTO_INCREMENT,
title char(255) NOT NULL,
content text,
PRIMARY KEY (id),
FULLTEXT (content));
#查找时:
mysql> select * from pull where match(content) against('查找的字符串');
5)查看索引
#方法一:
1.mysql> desc student;
+-----+
| Key |
+-----+
| PRI | 主键索引
| MUL | 普通索引
| UNI | 唯一键索引
+-----+
#方法二:
2.mysql> show index from student;
6)删除索引
mysql> alter table country drop index uni_name;
4.索引根据创建方式分类
1.在创建索引的时候,会把该列所有的数据按照btree的方式进行排序.
2.创建索引,会占用磁盘空间,所以不要每列都创建索引
3.在同一列上,尽量避免创建多个索引,可以创建但他又优先级,先走哪个就不会再走另一个索引了;
alter table student add index idx_name(name);
alter table country add unique key uni_name(name);
4.避免对大列建索引,在数据很长的列上创建前缀索引
1)前缀索引
#建表
create table student(
sid int not null primary key auto_increment comment '学号',
sname varchar(10) not null comment '姓名',
sage tinyint unsigned not null comment '年龄',
sgender enum('f','m') not null default 'm' comment '性别',
scometime datetime default now() comment '入学时间',
sbirthday datetime comment '学生生日',
class varchar(10) not null comment '学生班级');
#插入数据
mysql> insert into oldtian5(name,age,gender) values('alixkailiangle',18,'m'),('',84,'f');
#创建前缀索引
按照该列数据的前n个字母创建索引
mysql> alter table student add index idx_name(name(4));
2)联合索引
假如是相亲网站,肯定有多个条件,性别,身高,长相等等
根据访问次数或者喜好创建联合索引
#例子:
1.创建一个库
create database xiangqin;
use xiangqin
2.创建一个表
create table people (id int, name varchar(20), age tinyint, money int, gender enum('m','f'), hight int, weight int, figure varchar(10), looks varchar(10));
3.创建联合索引
alter table people add index idx_all(gender,money,figure,looks);
4.查看索引
show index from people;
5.插入多条数据
insert into people values(1,'fbb',18,800000000,'f',170,90,'good','beautiful');
insert into people values(2,'邱导',66,80,'m',150,190,'absurd','ugly');
#查询的时候有的时候走索引,有的时候不走索引
一定走索引
mysql> select * from people where gender=? money=? figure=? looks=?
一定不走索引
mysql> select * from people where money=? gender=? looks=? figure=?
部分走索引
mysql> select * from people where gender=? money=? looks=? figure=?
二、explain使用
之前总说到查询速度、查询效率,那使用什么去查看查询的快慢呢,就用explain
1.explain用法
我们之前查询过SQL
#1.查询中国和美国的城市 or 和 in
mysql> select * from world.city where countrycode='CHN' or countrycode='USA';
mysql> select * from world.city where countrycode in ('CHN','USA');
#2.union all (联合查询) 讲索引的时候再说
mysql> select * from world.city where countrycode='USA' union all select * from world.city where countrycode='CHN';
#3.explain用法
explain select * from city where countrycode='USA' or countrycode='CHN';
explain select * from city where countrycode in ('USA','CHN');
explain select * from world.city where countrycode='USA' union all select * from world.city where countrycode='CHN';
2.explain结果注解
mysql> explain select id from student where id=2;
#ID:
id相同,执行顺序由上至下
id不同,如果是子查询,id的序号会递增,id值越大优先级越高,越先被执行
#type:
查询使用了哪种类型
#possible_keys:
可能应用在这张表中的索引,一个或多个
#key:
实际使用的索引,如果为NULL,则没有使用索引
#key_len (可以使用前缀索引控制)
表示索引中使用的字节数,可通过该列计算查询中使用的索引的长度,在不损失精确性的情况下,长度越短越好。
#ref
级别是否在ref之上
#rows
根据表统计信息及索引选用情况,大致估算出找到所需的记录所需要读取的行数,也就是说,用的越少越好
#Extra
Using filesort:使用order by时
Using temporary:使用排序order by和分组查询group by时
2.查询数据种类
1)全表扫描
#1.什么是全表扫描
在explain语句结果中type为ALL,MySQL将遍历全表以找到匹配的行
#2.什么时候出现全表扫描?
1.业务确实要获取所有数据
mysql> explain select * from city;
2.不走索引导致的全表扫描
2.1 没索引
mysql> explain select * from city where District='shanghai';
#创建索引后速度会提升,变成索引扫描了
mysql> alter table city add index idx_District(District);
mysql> explain select * from city where District='shanghai';
2.2 索引创建有问题
2.3 语句有问题
2)索引扫描
#常见的索引扫描类型:
1)index 全索引扫描,index与ALL区别为index类型只遍历索引树(性能也不高)
mysql> explain select population from city;
2)range 范围查询,只检索给定范围的行,使用一个索引来选择行,一般来说,SQL语句只要达到range级别,就可以了
mysql> explain select * from city where countrycode in ('USA','CHN');
3)ref 精确查找,匹配条件有普通索引
#先给population列一个索引
mysql> alter table city add index idx_population(population);
#然后查询
mysql> explain select * from city where population=300000000;
4)eq_ref 类似ref,区别就在使用的索引是唯一索引
explain select city.name,city.countrycode,country.name from city join country on city.countrycode=country.code where city.population<100;
5)const 使用的索引是主键索引
mysql> explain select * from country where code='CHN';
6)system system是const类型的特例,当查询的表只有一行的情况下
mysql> delete from country where code != 'CHN';
#有外键删除不了
7)null 执行过程不用访问表或索引,直接选取索引列的最小值
mysql> explain select min(population) from city;
扩展:主键与外键
一个表里面的数据是由多个表中的主键组成的字段,那么在这个表中的字段称为其他表的外键;
一旦将所设计的数据库用于了生产环境,就很难对这些外键进行修改,所以在开发阶段就需要设计好主键和外键,外键一旦使用就不能更改
1.如果一个表里有两个外键字段指向两张表,那么每次往表里插入数据,就必须往两个外键对应的表里查询是否有对应数据。如果交由程序控制,这种查询过程就可以控制在我们手里,可以省略一些不必要的查询过程。但是如果由数据库控制,则是必须要去这两张表里判断。
2.若是在高并发大流量事务场景,使用外键更容易造成死锁。
3.迁移数据库或者分库分表的时候,外键很可能出现无法生效的问题。
4.如果没有专业DBA是很难操作外键的
主键 | 外键 | 索引 | |
---|---|---|---|
定义: | 唯一标识一条记录,不能有重复的,不允许为空 | 表的外键是另一表的主键, 外键可以有重复的, 可以是空值 | 该字段没有重复值,但可以有一个空值 |
作用: | 用来保证数据完整性 | 用来和其他表建立联系用的,保证表间数据的关系“始终完整” | 是提高查询排序的速度 |
个数: | 主键只能有一个 | 一个表可以有多个外键 | 一个表可以有多个惟一索引 |
三、索引建立
1.建立索引的原则
主键只能使用一个
但是使用第三方工具可以设置多个主键,可以创建测试,查看
但是第三方设置的主键还是可以重复插入,他相当于对一个主键建立了联合索引,没有任何意义,很坑
1.如果可以创建唯一索引,就创建唯一索引(该列的数据不重复),查询速度快
#数据去重
mysql> select distinct(name) from qiudao3;
#去重之后计数,当值与没去重条数一致时可以为该列加唯一键
mysql> select count(distinct(name)) from qiudao3;*
2.为经常要排序,分组,联合操作的列,创建联合索引
经常需要ORDER BY、GROUP BY、DISTINCT和UNION等操作的字段,排序操作会浪费很多时间。
如果为其建立索引,可以有效地避免排序操作
3.为常作为查询条件的字段建立索引
4.尽量使用前缀来索引
创建索引的时候,要给该列所有数据进行排序
5.限制索引的数目
索引的数目不是越多越好。每个索引都需要占用磁盘空间,索引越多,需要的磁盘空间就越大。
修改表时,对索引的重构和更新很麻烦。越多的索引,会使更新表变得很浪费时间。
6.删除不再使用或者很少使用的索引
表中的数据被大量更新,或者数据的使用方式被改变后,原有的一些索引可能不再需要。数据库管理员应当定期找出这些索引,将它们删除,从而减少索引对更新操作的影响。
2.什么时候不走索引?
1)没有查询条件,或者查询条件没有建立索引
#没有条件的情况
mysql> explain select * from world.city;
mysql> explain select * from world.city where 1=1;
#没建立索引的列做条件
mysql> explain select * from world.city where name='shanghai';
2)查询结果集是原表中的大部分数据,应该是25%以上
#如果生产中,必须有这种全表扫描的需求不走索引
mysql> explain select * from world.city where population > 50;
#如果业务允许,可以使用limit控制,可以走索引
mysql> explain select * from world.city where population>50 limit 10;
#如果业务不允许,可以使用缓存
前面加上缓存,memcached,redis
3)索引本身失效,统计数据不真实
反复修改,插入数据,索引被修改坏了,每次都会进行排序
4)查询条件使用函数在索引列上或者对索引列进行运算,运算包括(+,-,*等)
mysql> explain select * from world.city where id=9;
#查询ID等于9的数据,会导致不走索引
mysql> explain select * from world.city where id-1=8;
#查询ID等于9的数据,可以在后面作加减
mysql> explain select * from world.city where id=8+1;
5)隐式转换,会导致索引失效
#创建一个表
create table test(id int, name varchar(20), phonenum varchar(10));
#插入几条数据
insert into test values(1,'jc','110'),(2,'xf',119),(3,'jh',120);
#建立索引,没有相同值可以给唯一索引
alter table test unique key idx_num(phonenum);
#查看索引
show index from test;
#查询语句级别
不走索引
explain select * from test where phonenum=110;
走索引
explain select * from test where phonenum='110'; #引号可能导致大事故
因为这一列是varchar类型,必须以字符来查询
6)<> 和 not in , or 也不走索引
mysql> explain select * from test where phonenum <> '120';
mysql> explain select * from test where phonenum not in (120);
mysql> explain select * from test where telnum='110' or telnum='119';
#使用union all可以走索引
mysql> explain select * from test where telnum='110' union all select * from test where telnum='119';
7)like模糊查询%在最前面,不走索引
#%在前面不走索引
mysql> explain select * from city where countrycode like '%HN';
#%在后面,走索引
mysql> explain select * from city where countrycode like 'CH%';
#放在后面也不是一定了,因为涉及到第二点结果的占总数据的比例
#%在最前面的搜索需求,建议使用elasticsearch ES ELK(E) 搜索引擎式的 数据库
8)单独引用联合索引里非第一位置的索引列
三、索引建立
1.建立索引的原则
主键只能使用一个
但是使用第三方工具可以设置多个主键,可以创建测试,查看
但是第三方设置的主键还是可以重复插入,他相当于对一个主键建立了联合索引,没有任何意义,很坑
1.如果可以创建唯一索引,就创建唯一索引(该列的数据不重复),查询速度快
#数据去重
mysql> select distinct(name) from qiudao3;
#去重之后计数,当值与没去重条数一致时可以为该列加唯一键
mysql> select count(distinct(name)) from qiudao3;*
2.为经常要排序,分组,联合操作的列,创建联合索引
经常需要ORDER BY、GROUP BY、DISTINCT和UNION等操作的字段,排序操作会浪费很多时间。
如果为其建立索引,可以有效地避免排序操作
3.为常作为查询条件的字段建立索引
4.尽量使用前缀来索引
创建索引的时候,要给该列所有数据进行排序
5.限制索引的数目
索引的数目不是越多越好。每个索引都需要占用磁盘空间,索引越多,需要的磁盘空间就越大。
修改表时,对索引的重构和更新很麻烦。越多的索引,会使更新表变得很浪费时间。
6.删除不再使用或者很少使用的索引
表中的数据被大量更新,或者数据的使用方式被改变后,原有的一些索引可能不再需要。数据库管理员应当定期找出这些索引,将它们删除,从而减少索引对更新操作的影响。
2.什么时候不走索引?
1)没有查询条件,或者查询条件没有建立索引
#没有条件的情况
mysql> explain select * from world.city;
mysql> explain select * from world.city where 1=1;
#删除索引
mysql> alter table country drop index uni_name;
#没建立索引的列做条件
mysql> explain select * from world.city where name='shanghai';
2)查询结果集是原表中的大部分数据,应该是25%以上
#如果生产中,必须有这种全表扫描的需求不走索引
mysql> explain select * from world.city where population > 50;
#如果业务允许,可以使用limit控制,可以走索引
mysql> explain select * from world.city where population>50 limit 10;
#如果业务不允许,可以使用缓存
前面加上缓存,memcached,redis
3)索引本身失效,统计数据不真实
反复修改,插入数据,索引被修改坏了,每次都会进行排序
4)查询条件使用函数在索引列上或者对索引列进行运算,运算包括(+,-,*等)
mysql> explain select * from world.city where id=9;
#查询ID等于9的数据,会导致不走索引
mysql> explain select * from world.city where id-1=8;
#查询ID等于9的数据,可以在后面作加减
mysql> explain select * from world.city where id=8+1;
5)隐式转换,会导致索引失效
#创建一个表
create table test(id int, name varchar(20), phonenum varchar(10));
#插入几条数据
insert into test values(1,'jc','110'),(2,'xf','119'),(3,'jh','120');
#建立索引,没有相同值可以给唯一索引
alter table test unique key idx_num(phonenum);
#查看索引
show index from test;
#查询语句级别
不走索引
explain select * from test where phonenum=110;
走索引
explain select * from test where phonenum='110'; #引号可能导致大事故
因为这一列是varchar类型,必须以字符来查询
6)<> 和 not in , or 也不走索引
mysql> explain select * from test where phonenum <> '120';
mysql> explain select * from test where phonenum not in (120);
mysql> explain select * from test where telnum='110' or telnum='119';
#使用union all可以走索引
mysql> explain select * from test where telnum='110' union all select * from test where telnum='119';
7)like模糊查询%在最前面,不走索引
#%在前面不走索引
mysql> explain select * from city where countrycode like '%HN';
#%在后面,走索引
mysql> explain select * from city where countrycode like 'CH%';
#放在后面也不是一定了,因为涉及到第二点结果的占总数据的比例
#%在最前面的搜索需求,建议使用elasticsearch ES ELK(E) 搜索引擎式的 数据库
8)单独引用联合索引里非第一位置的索引列
二、MySQL存储引擎
innodb
MySQL自己的"文件系统"
mysqld程序结构:
1)连接层:
验证用户的合法性
提供两种连接方式(TCP/IP socket)
建立一个与SQL层交互的线程
2)sql层
1.接收连接层传来的SQL语句
2.验证语法
3.验证语义(DML,DDL,DCL,DQL) 检查你输入的SQL语句是 select insert update delete... grant
4.解析器:解析你的SQL语句,生成多种执行计划
5.优化器:接收解析器传来的多种执行计划,选择最优的一种
6.执行器:将优化器选择出的最优的SQL,执行
6.1 建立一个与存储引擎层 交互的线程
6.2 将执行语句交给存储引擎层,取数据 接收存储引擎层,结构化成表的数据结果
7.如果你的前端有缓存,写缓存
8.记录日志(binlog)
3)存储引擎层
1.接收到SQL层传来的SQL语句
2.与磁盘交互,取数据,结构化成表的形式,返回给SQL层
3.建立一个与SQL层交互的线程
1.MySQL 提供的存储引擎
01)InnoDB
用于事务处理应用程序,支持外键和行级锁。如果应用对事物的完整性有比较高的要求,在并发条件下要求数据的一致性,数据操作除了插入和查询之外,还包括很多更新和删除操作,那么InnoDB存储引擎是比较合适的。InnoDB除了有效的降低由删除和更新导致的锁定,还可以确保事务的完整提交和回滚,对于类似计费系统或者财务系统等对数据准确要求性比较高的系统都是合适的选择。
02)MyISAM
只是读取和插入,不做修改和删除使用这个,MyISAM对事务的完整性、并发性要求不高
03)MEMORY 支持hash索引,使用redis替换
将所有的数据保存在内存中,可以提供极快的访问。Memory的缺陷是对表的大小有限制,虽然数据库因为异常终止的话数据可以正常恢复,但是一旦数据库关闭,存储在内存中的数据都会丢失。
04)ARCHIVE
05)FEDERATED
06)EXAMPLE
07)BLACKHOLE
08)MERGE
09)NDBCLUSTER
10)CSV
#还可以使用第三方存储引擎:
01)MySQL当中插件式的存储引擎类型
02)MySQL的两个分支
03)perconaDB
04)mariaDB
#我们可以查看我们库里面哪些是myisam哪些是innodb存储引擎
#查看当前MySQL支持的存储引擎类型
mysql> show engines
#查看innodb的表有哪些
mysql> select table_schema,table_name,engine from information_schema.tables where engine='innodb';
#查看myisam的表有哪些
mysql> select table_schema,table_name,engine from information_schema.tables where engine='myisam';
TABLES表:提供了关于数据库中的表的信息
mysql> select * from tables limit 1\\G
mysql> select * from tables where TABLE_NAME='city'\\G
columns表:提供了关于数据库中表的列的信息
mysql> select * from columns\\G
STATISTICS表:表索引的信息
COLLATIONS表:提供校验规则和字符集对应关系
Table_catalog 数据表登记目录
Table_schema 数据表所属的数据库名
Table_name 表名称
Table_type 表类型[system view|base table] 系统表 ,数据表
Engine 使用的数据库引擎[MyISAM|CSV|InnoDB]
Version 版本,默认值10
Row_format 行格式[Compact|Dynamic|Fixed]
Table_rows 表里所存多少行数据
Avg_row_length 平均行长度
Data_length 数据长度
Max_data_length 最大数据长度
Index_length 索引长度
Data_free 空间碎片 刚刚用过的暂时不再使用
Auto_increment 做自增主键的自动增量当前值 可以通过导出再导入数据进行释放
Create_time 表的创建时间
Update_time 表的更新时间
Check_time 表的检查时间
Table_collation 表的字符校验编码集
Checksum 校验和
Create_options 创建选项
Table_comment 表的注释、备注
CREATE TABLE student(gid int primary key COMMENT '列注释') COMMENT='表注释';
#查看当前MySQL支持的存储引擎类型
mysql> show engines
#查看innodb的表有哪些
mysql> select table_schema,table_name,engine from information_schema.tables where engine='innodb';
#查看myisam的表有哪些
mysql> select table_schema,table_name,engine from information_schema.tables where engine='myisam';
2.innodb和myisam物理上的区别
myisam:
-rw-rw----. 1 mysql mysql 1212 Jul 15 23:36 user.MYD #密码
-rw-rw----. 1 mysql mysql 2048 Jul 15 23:36 user.MYI #主机域
-rw-rw----. 1 mysql mysql 10684 Jul 15 23:36 user.frm #表结构
#cat查看不了这个文件
使用strings user.MYD
innodb:
-rw-rw----. 1 mysql mysql 8710 Jul 16 01:41 city.frm #表结构
-rw-rw----. 1 mysql mysql 819200 Jul 16 01:41 city.ibd #表数据
3.innodb的核心特性
#重点:
MVCC 多版本并发控制
事务
行级锁 innodb支持行级锁,myisam是表级锁 锁定力度就决定了速度了
备份和恢复 innodb支持支持热备,myisam不支持
自动故障恢复 (CSR) Crash Safe Recovery
4.存储引擎相关命令
1)查看当前的存储引擎
SELECT @@default_storage_engine;
2)查看表的存储引擎
SHOW CREATE TABLE City\\G
SHOW TABLE STATUS LIKE 'CountryLanguage'\\G
SELECT TABLE_NAME, ENGINE FROM
INFORMATION_SCHEMA.TABLES
WHERE TABLE_NAME = 'City'
AND TABLE_SCHEMA = 'world'\\G
3)配置文件修改存储引擎
vim /etc/my.cnf
[mysqld]
default-storage-engine=innodb
4)临时修改存储引擎
#在MySQL命令行中临时设置
SET @@storage_engine=myisam
#查看
SELECT @@default_storage_engine;
5)建表时修改存储引擎
CREATE TABLE test(id INT) ENGINE=myisam;
三、企业真实案例
1.项目背景:
公司原有的架构:一个展示型的网站,LAMT,MySQL5.1.77版本(MYISAM),50M数据量。
2.小问题不断:
1、表级锁:对表中任意一行数据修改类操作时,整个表都会锁定,对其他行的操作都不能同时进行。
2、不支持故障自动恢复(CSR):当断电时有可能会出现数据损坏或丢失的问题。
3.如何解决:
1、提建议将现有的MYISAM引擎替换为Innodb,将版本替换为5.6.38
1)如果使用MYISAM会产生”小问题”,性能安全不能得到保证,使用innodb可以解决这个问题。
2)5.1.77版本对于innodb引擎支持不够完善,5.6.38版本对innodb支持非常完善了。
2、实施过程和注意要素
1)备份生产库数据(mysqldump)
[root@db01 ~]# mysqldump -uroot -p123 -A --triggers -R --master-data=2 >/tmp/full.sql
2)准备一个5.6.38版本的新数据库
3)对备份数据进行处理(将engine字段替换)
[root@db01 ~]# sed -i 's#ENGINE=MYISAM#ENGINE=INNODB#g' /tmp/full.sql
#注意:修改之后导入数据库的时候mysql库会少表,因为有些系统表不能需改称innodb搜索引擎,所以迁移数据时,只迁移数据类型的库,不要迁移系统库
4)将修改后的备份恢复到新库
5)应用测试环境连接新库,测试所有功能
6)停应用,将备份之后的生产库发生的新变化,补偿到新库
7)应用割接到新数据库
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tRREoaDn-1625199510107)(C:\\Users\\12402\\AppData\\Roaming\\Typora\\typora-user-images\\1587477720967.png)]
四、Innodb存储引擎——表空间介绍
5.5版本以后出现共享表空间概念
表空间的管理模式的出现是为了数据库的存储更容易扩展
5.6版本中默认的是独立表空间
1.共享表空间
1)存储的内容
1.系统数据
2.undo redo,undo,事务日志,5.6中undo存储在共享表空间,redo是ib_logfile0,在MySQL5.7中,undo也是独立
3.临时表 查出来的数据生成一个表,临时的
2)概念
类似于LVM逻辑卷,是动态扩展的
默认只有12M,会根据数据的量慢慢变越来越大
优点:可以将表空间分成多个文件存放到各个磁盘上(表空间文件大小不受表大小的限制,如一个表可以分布在不同的文件上)。数据和文件放在一起方便管理。
缺点:所有的数据和索引存放到一个文件中,虽然可以把一个大文件分成多个小文件,但是多个表及索引在表空间中混合存储,这样对于一个表做了大量删除操作后表空间中将会有大量的空隙,特别是对于统计分析,日值系统这类应用最不适合用共享表空间。
3)查看共享表空间
mysql> show variables like '%path%';
+----------------------------------+------------------------+
| Variable_name | Value |
+----------------------------------+------------------------+
| innodb_data_file_path | ibdata1:12M:autoextend |
| sha256_password_private_key_path | private_key.pem |
| sha256_password_public_key_path | public_key.pem |
| ssl_capath | |
| ssl_crlpath | |
+----------------------------------+------------------------+
5 rows in set (0.01 sec)
4)修改共享表空间
#1.编辑配置文件
[root@db01 ~]# vim /etc/my.cnf
[mysqld]
innodb_data_file_path=ibdata1:50M;ibdata2:50M:autoextend
#配置一个就够用了,为什么要配置两个呢?
第一个共享表空间数据达到50M以后,他会往第二个表空间里面写数据,当第二个共享表空间数据也达到50M以后会动态扩容,这个文件会越来越大,就像日志一样;
这样就会导致一个问题,当越来越多的数据增加的时候,ibdata也会持续膨胀,有的达到几十G,上百G
那么,,当前存储数据的磁盘分区满的时候,要怎么样去扩展数据空间呢?
#2.修改完配置文件重启
[root@db03 ~]# systemctl start mysql
启动会报错或者启动不了
查看日志
[root@db03 ~]# less /usr/local/mysql/data/db03.err
2020-04-21 22:26:00 50917 [ERROR] InnoDB: Data file ./ibdata1 is of a different size 768 pages (rounded down to MB) than specified in t
he .cnf file 3200 pages!
#3.报错说明共享表空间大小不一致,我们要把共享表空间修改为当前共享表空间的大小才行
[root@db01 ~]# vim /etc/my.cnf
[mysqld]
innodb_data_file_path=ibdata1:12M;ibdata2:50M:autoextend
#4.修改后重启
[root@db03 ~]# systemctl start mysql
[root@db03 ~]# ps -ef | grep [m]ysql
mysql 51079 1 19 22:32 ? 00:00:00 /usr/local/mysql/bin/mysqld --defaults-file=/etc/my.cnf
2.独立表空间
对于用户自主创建的表,会采用此种模式,每个表由一个独立的表空间进行管理
优点:
1.每个表都有自已独立的表空间。
2.每个表的数据和索引都会存在自已的表空间中。
3.可以实现单表在不同的数据库中移动。
4.空间可以回收(除drop table操作处,表空不能自已回收)
a.Drop table操作自动回收表空间,如果对于统计分析或是日值表,删除大量数据后可以通过:alter table TableName engine=innodb;回缩不用的空间。
b.对于使innodb-plugin的Innodb使用turncate table也会使空间收缩。
c.对于使用独立表空间的表,不管怎么删除,表空间的碎片不会太严重的影响性能,而且还有机会处理。
缺点:
1.单表增加过大,如超过100个G。
2.相比较之下,使用独占表空间的效率以及性能会更高一点。
1)查看独立表空间
#物理查看
[root@db01 ~]# ll /application/mysql/data/world/
-rw-rw---- 1 mysql mysql 688128 Aug 14 16:23 city.ibd
#命令行查看
mysql> show variables like '%per_table%';
innodb_file_per_table=ON
企业案例
在没有备份数据的情况下,数据库突然断电导致表空间或者表结构损坏,打不开数据库。
2)模拟数据库表损坏
#1.将db02的数据目录下面的world打包
[root@db03 ~]# cd /usr/local/mysql/data/
[root@db03 data]# tar zcf world.tar.gz world
#2.把数据拷贝到db01
[root@db03 data]# scp world.tar.gz 10.0.0.51:/tmp/
#3.到db01上解压文件到mysql的数据目录
[root@db01 ~]# cd /service/mysql/data/
[root@db01 data]# tar xf /tmp/world.tar.gz -C ./
#4.登录数据库查看
mysql> show databases;
mysql> use world;
mysql> show tables;
mysql> select * from world;
ERROR 1146 (42S02): Table 'world.world' doesn't exist
#数据库存在,表也在却无法查看使用
3)解决数据库表损坏问题
#1.找到建表语句
mysql> show create table city;
#创建新表
CREATE TABLE `city_new` (
`ID` int(11) NOT NULL AUTO_INCREMENT,
`Name` char(35) NOT NULL DEFAULT '',
`CountryCode` char(3) NOT NULL DEFAULT '',
`District` char(20) NOT NULL DEFAULT '',
`Population` int(11) NOT NULL DEFAULT '0',
PRIMARY KEY (`ID`),
KEY `CountryCode` (`CountryCode`),
KEY `idx_population` (`Population`),
#外键语句,建议删除
CONSTRAINT `city_ibfk_1` FOREIGN KEY (`CountryCode`) REFERENCES `country` (`Code`)
) ENGINE=InnoDB AUTO_INCREMENT=2252 DEFAULT CHARSET=latin1
#新建的表是没有数据的,我们要拿到他的表数据
#2.移除city_new的表空间
mysql> mysql> alter table city_new discard tablespace;
#3.物理拷贝city的表空间,并授权
[root@db01 world]# cp city.ibd city_new.ibd
[root@db01 world]# chown -R mysql.mysql city_new.ibd
#4.进入数据库查看表数据
mysql> use world;
mysql> select * from city_new;
ERROR 1814 (HY000): Tablespace has been discarded for table 'city_new'
#5.读取city_new表空间
mysql> alter table city_new import tablespace;
#6.查询数据
mysql> select * from city_new;
+------+--------+-------------+----------+------------+
| ID | Name | CountryCode | District | Population |
+------+--------+-------------+----------+------------+
| 2251 | Pingyi | CHN | Shandong | 89373 |
+------+--------+-------------+----------+------------+
1 row in set (0.00 sec)
#7.物理删除旧表
[root@db01 world]# rm -rf city.ibd
#8.修改表名
mysql> alter table city_new rename city;
五、Innodb核心特性——事务
1.什么是事务
#主要针对DML语句(update,delete,insert)增删改都伴随着事务
一组数据操作执行步骤,这些步骤被视为一个工作单元:
1)用于对多个语句进行分组
2)可以在多个客户机并发访问同一个表中的数据时使用
所有步骤都成功或都失败
1)如果所有步骤正常,则执行
2)如果步骤出现错误或不完整,则取消
2.事务的通俗理解
#伴随着“交易”出现的数据库概念
我们理解的“交易”是什么?
1)物与物的交换(古代)
2)货币现金与实物的交换(现代1)
3)虚拟货币与实物的交换(现代2)
4)虚拟货币与虚拟实物交换(现代3)
数据库中的“交易”是什么?
1)事务又是如何保证“交易”的“和谐”?
2)ACID
3.事务演示
#1.创建一个表
mysql> create table jiaoyi(id int,name varchar(10),money int );
#2.插入一条数据
mysql> insert into jiaoyi values(1,'gcc',1000);
Query OK, 1 row affected (0.01 sec)
mysql> insert into jiaoyi values(2,'zzy',2000);
Query OK, 1 row affected (0.01 sec)
mysql> select * from jiaoyi;
+------+------+-------+
| id | name | money |
+------+------+-------+
| 1 | gcc | 1000 |
| 2 | zzy | 2000 |
+------+------+-------+
2 rows in set (0.00 sec)
#3.再开一个xshell窗口,查看数据库
mysql> select * from jiaoyi;
#4.修改数据
mysql> update jiaoyi set money=2000 where name='gcc';
#5.两端都可以查看到数据变化
数据产生变化,但是还没有完成转账,因为还有一条数据没有改变
一定要在事务中进行数据的改变
#6.在事务中进行数据变化
mysql> begin;
mysql> update jiaoyi set money=3000 where name='gcc';
#这个时候另一个窗口是看不到数据变化的,因为事务没有结束
mysql> update jiaoyi set money=1000 where name='zzy';
mysql> commit;
#这个时候远端才能看见数据的变化,因为事务已经结束
#7.如果数据的变化不符合逻辑
mysql> begin;
mysql> update jiaoyi set money=-1000 where name='zzy';
mysql> select * from jiaoyi;
#由程序判断执行回滚
mysql> rollback;
发红包就是这个原理
或者买火车票
游戏保存
4.一个成功事务的生命周期:
begin;
SQL1
SQL2
SQL3
...
commit;
5.一个失败事务的生命周期:
begin;
SQL1
SQL2
SQL3
...
rollback;
6.事务的特性 ACID
Atomic(原子性)
所有语句作为一个单元全部成功执行或全部取消。
Consistent(一致性)
如果数据库在事务开始时处于一致状态,则在执行该事务期间将保留一致状态。
Isolated(隔离性)
事务之间不相互影响。
Durable(持久性)
事务成功完成后,所做的所有更改都会准确地记录在数据库中。所做的更改不会丢失。
六、事务的控制语句
事务的控制语句(DML):在MySQL中,只要执行一个DML会自动开启一个事务
START TRANSACTION(或 BEGIN):显式开始一个新事务 #开启事务
SAVEPOINT:分配事务过程中的一个位置,以供将来引用 #保存,存档
COMMIT:永久记录当前事务所做的更改 #提交
ROLLBACK:取消当前事务所做的更改 #回滚
ROLLBACK TO SAVEPOINT:取消在 savepoint 之后执行的更改
RELEASE SAVEPOINT:删除 savepoint 标识符
SET AUTOCOMMIT:为当前连接禁用或启用默认 autocommit 模式
1.自动提交
#我们所有的DML命令都伴随着一个事务,我们每次执行完就会得到结果是因为开启了自动提交
#查看自动提交
mysql> show variables like 'autocommit';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| autocommit | ON |
+---------------+-------+
#永久关闭:
vim /etc/my.cnf
[mysqld]
autocommit=0
#临时关闭:
set autocommit=0;
2.事务的隐式提交
1)现在版本在开启事务时,不需要手工begin,只要你输入的是DML语句,就会自动开启事务。
2)有些情况下事务会被隐式提交
1.在你执行事务的期间,如果使用DDL或者是DCL会自动将上一个事务提交
2.在你执行事务的期间,如果使用begin;start transaction;也会将上一个事务提交
3.在你执行事务的期间,如果使用锁表(lock table)解锁(unlock),也会自动提交
4.load data infile(导数据的时候) 也会自动提交事务
5.select for update ,也会自动提交
mysql> select * from jiaoyi where id=2 for update;
6.在autocommit=1的时候,也会自动提交
update set xxx where xxx=1;
commit;
insert into xxx;
begin;
update set;
create database;
delete;
七、事务日志
1.redo log
redo:在事务ACID过程中,实现的是“D”持久化的作用。
WAL:日志优先写,write ahead log,数据修改后不是第一时间存储到磁盘的,先存储到日志,然后写入磁盘
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ov2ykw5b-1625199510110)(C:\\Users\\12402\\AppData\\Roaming\\Typora\\typora-user-images\\1587486167023.png)]
事务id:txid
日志版本号:lsn
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ufm3KLe6-1625199510112)(C:\\Users\\12402\\AppData\\Roaming\\Typora\\typora-user-images\\1587486506303.png)]
以上是关于linux12 -MYSQL数据库 -->07数据库索引和存储引擎的主要内容,如果未能解决你的问题,请参考以下文章