MySQL进阶学习

存储引擎

MySQL进阶学习_第1张图片

 1).连接层

最上层是一些客户端和链接服务,包含本地sock通信和大多数基于客户端/服务端工具实现的类似于TCP/IP的通信。主要完成一些类似于连接处理、授权认证、及相关的安全方案。在该层上引入了线程池的概念,为通过认证安全接入的客户端提供线程。同样在该层上可以实现基于SSL的安全链接。服务器也会为安全接入的每个客户端验证它所具有的操作权限。

2).服务层

第二层架构主要完成大多数的核心服务功能,如SQL接口,并完成缓存的查询,SQL的分析和优化,部分内置函数的执行。所有跨存储引擎的功能也在这一层实现,如过程、函数等。在该层,服务器会解析查询并创建相应的内部解析树,并对其完成相应的优化如确定表的查询的顺序,是否利用索引等,最后生成相应的执行操作。如果是select语句,服务器还会查询内部的缓存,如果缓存空间足够大,这样在解决大量读操作的环境中能够很好的提升系统的性能。

3).引擎层

存储引擎层,存储引擎真正的负责了MySQL中数据的存储和提取,服务器通过API和存储引擎进行通信。不同的存储引擎具有不同的功能,这样我们可以根据自己的需要,来选取合适的存储引擎。数据库中的索引是在存储引擎层实现的。

4).存储层

数据存储层,主要是将数据(如:redolog、undolog、数据、索引、二进制日志、错误日志、查询日志、慢查询日志等)存储在文件系统之上,并完成与存储引擎的交互。

和其他数据库相比,MySQL有点与众不同,它的架构可以在多种不同场景中应用并发挥良好作用。主要体现在存储引擎上,插件式的存储引擎架构,将查询处理和其他的系统任务以及数据的存储提取分离。这种架构可以根据业务的需求和实际需要选择合适的存储引擎。

存储引擎就是存储数据、建立索引、更新/查询数据等技术的实现方式。存储引擎是基于表的,而不是基于库的,所以存储引擎也可被称为表类型。我们可以在创建表的时候,来指定选择的存储引擎,如果没有指定将自动选择默认的存储引擎。

1).建表时指定存储引擎

create table dept
(
    deptno   int         not null
        primary key,
    deptname varchar(50) null,
    loc      varchar(50) null
) engine = InnoDB;

查看数据库支持的存储引擎  默认是 InnoDB

show engines;

MySQL进阶学习_第2张图片

存储引擎特点

InnoDB

InnoDB是一种兼顾高可靠性和高性能的通用存储引擎,在MySQL 5.5之后,InnoDB是默认的MySQL存储引擎。

特点: 事务  行级锁  外键

DML操作遵循ACID模型,支持事务

行级锁,提高并发访问性能;

支持 FOREIGN KEY约束,保证数据的完整性和正确性;

文件:

xxx.ibd:xxx代表的是表名,innoDB引擎的每张表都会对应这样一个表空间文件,存储该表的表结构(frm-早期的、sdi-新版的)、数据和索引。参数:innodb_file_per_table

参数:innodb_file_per_table

逻辑存储结构

MySQL进阶学习_第3张图片

表空间: InnoDB存储引擎逻辑结构的最高层,ibd文件其实就是表空间文件,在表空间中可以包含多个Segment段。

段:表空间是由各个段组成的,常见的段有数据段、索引段、回滚段等。InnoDB中对于段的管理,都是引擎自身完成,不需要人为对其控制,一个段中包含多个区。

区:区是表空间的单元结构,每个区的大小为1M。默认情况下,InnoDB存储引擎页大小为16K,即一个区中一共有64个连续的页。

页:页是组成区的最小单元,页也是InnoDB存储引擎磁盘管理的最小单元,每个页的大小默认为16KB。为了保证页的连续性,InnoDB存储引擎每次从磁盘申请4-5个区。

行: InnoDB存储引擎是面向行的,也就是说数据是按行进行存放的,在每一行中除了定义表时所指定的字段以外,还包含两个隐藏字段(后面会详细介绍)

MyISAM

MyISAM是MySQL早期的默认存储引擎。

特点:

不支持事务,不支持外键

支持表锁,不支持行锁

访问速度快

Memory

Memory引擎的表数据时存储在内存中的,由于受到硬件问题、或断电问题的影响,只能将这些表作为临时表或缓存使用。

特点:

hash索引(默认)

以上三者的区别和特点

MySQL进阶学习_第4张图片

面试题: 

InnoDB引擎与MyISAM引擎的区别?

①.InnoDB引擎,支持事务,而MyISAM不支持。

②.InnoDB引擎,支持行锁和表锁,而MyISAM仅支持表锁,不支持行锁。

③.InnoDB引擎,支持外键,而MyISAM是不支持的。

主要是上述三点区别,当然也可以从索引结构、存储限制等方面,更加深入的回答,具体参考如下官方文档:

https://dev.mysql.com/doc/refman/8.0/en/innodb-introduction.htmlhttps://dev.mysql.com/doc/refman/8.0/en/myisam-storage-engine.html

存储引擎选择

在选择存储引擎时,应该根据应用系统的特点选择合适的存储引擎。对于复杂的应用系统,还可以根据实际情况选择多种存储引擎进行组合。

InnoDB:是Mysql的默认存储引擎,支持事务、外键。如果应用对事务的完整性有比较高的要求,在并发条件下要求数据的一致性,数据操作除了插入和查询之外,还包含很多的更新、删除操作,那么InnoDB存储引擎是比较合适的选择。

MyISAM:如果应用是以读操作和插入操作为主,只有很少的更新和删除操作,并且对事务的完整性、并发性要求不是很高,那么选择这个存储引擎是非常合适的。

MEMORY:将所有数据保存在内存中,访问速度快,通常用于临时表及缓存。MEMORY的缺陷就是对表的大小有限制,太大的表无法缓存在内存中,而且无法保障数据的安全性。

索引

介绍:

索引(index)是帮助MySQL高效获取数据的数据结构(有序)。在数据之外,数据库系统还维护着满足特定查找算法的数据结构,这些数据结构以某种方式引用(指向)数据,这样就可以在这些数据结构上实现高级查找算法,这种数据结构就是索引。

特点:

优势:

提高数据检索的效率,降低数据库的IO成本

通过索引列对数据进行排序,降低数据排序的成本,降低CPU的消耗。

劣势:

索引大大提高了查询效率,同时却也降低更新表的速度,如对表进行INSERT、UPDATE、DELETE时,效率降低。

索引结构:

MySQL的索引是在存储引擎层实现的,不同的存储引擎有不同的索引结构,主要包含以下几种:

索引结构 描述
B+Tree索引 最常见的索引类型,大部分引擎都支持B+树索引
Hash索引 底层数据结构是用哈希表实现的,只有精确匹配索引列的查询才有效,不支持范围查询
R-tree(空间索引) 空间索引是MyISAM引擎的一个特殊索引类型,主要用于地理空间数据类型,通常使用较少
Full-text(全文索引) 是一种通过建立倒排索引,快速匹配文档的方式。类似于Lucene,Solr,ES

上述是MySQL中所支持的所有的索引结构,接下来,我们再来看看不同的存储引擎对于索引结构的支持情况。

索引 InnoDB MyISAM Memory
B+tree索引 支持 支持 支持
Hash索引 不支持 不支持 支持
R-tree索引 不支持 支持 不支持
Full-text 5.6版本之后支持 支持 不支持

注意:我们平常所说的索引,如果没有特别指明,都是指B+树结构组织的索引。

动画显示各种数据结构的网站:

Data Structure Visualization

MySQL的索引结构分析

用二叉树的数据结构,比较理想的结构如下:

MySQL进阶学习_第5张图片

 此时大家可能会想到,我们可以选择红黑树,红黑树是一颗自平衡二叉树,那这样即使是顺序插入数据,最终形成的数据结构也是一颗平衡的二叉树,结构如下:

MySQL进阶学习_第6张图片

 B-Tree

B-Tree,B树是一种多叉路衡查找树,相对于二叉树,B树每个节点可以有多个分支,即多叉。以一颗最大度数(max-degree)为5(5阶)的b-tree为例,那这个B树每个节点最多存储4个key,5个指针:

MySQL进阶学习_第7张图片

5阶的B树,每一个节点最多存储4个key,对应5个指针。

一旦节点存储的key数量到达5,就会裂变,中间元素向上分裂。

在B树中,非叶子节点和叶子节点都会存放数据。 

B+Tree

B+Tree是B-Tree的变种,我们以一颗最大度数(max-degree)为4(4阶)的b+tree为例,来看一下其结构示意图:

MySQL进阶学习_第8张图片

绿色框框起来的部分,是索引部分,仅仅起到索引数据的作用,不存储数据。

红色框框起来的部分,是数据存储部分,在其叶子节点中要存储具体的数据。 

B+Tree与B-Tree相比,主要有以下三点区别:

所有的数据都会出现在叶子节点。

叶子节点形成一个单向链表。

非叶子节点仅仅起到索引数据作用,具体的数据都是在叶子节点存放的。

上述我们所看到的结构是标准的B+Tree的数据结构,接下来,我们再来看看MySQL中优化之后的B+Tree。

MySQL索引数据结构对经典的B+Tree进行了优化。在原B+Tree的基础上,增加一个指向相邻叶子节点的链表指针,就形成了带有顺序指针的B+Tree,提高区间访问的性能,利于排序。

MySQL进阶学习_第9张图片

 Hash

MySQL中除了支持B+Tree索引,还支持一种索引类型---Hash索引。

哈希索引就是采用一定的hash算法,将键值换算成新的hash值,映射到对应的槽位上,然后存储在hash表中。

MySQL进阶学习_第10张图片

 如果两个(或多个)键值,映射到一个相同的槽位上,他们就产生了hash冲突(也称为hash碰撞),可以通过链表来解决。

MySQL进阶学习_第11张图片

特点:

A. Hash索引只能用于对等比较(=,in),不支持范围查询(between,>,<,...)

B.无法利用索引完成排序操作

C.查询效率高,通常(不存在hash冲突的情况)只需要一次检索就可以了,效率通常要高于B+tree索引 

存储引擎支持

在MySQL中,支持hash索引的是Memory存储引擎。而InnoDB中具有自适应hash功能,hash索引是InnoDB存储引擎根据B+Tree索引在指定条件下自动构建的。

面试题:为什么InnoDB存储引擎选择使用B+tree索引结构?

A.相对于二叉树,层级更少,搜索效率高;

B.对于B-tree,无论是叶子节点还是非叶子节点,都会保存数据,这样导致一页中存储的键值减少,指针跟着减少,要同样保存大量数据,只能增加树的高度,导致性能降低;

C.相对Hash索引,B+tree支持范围匹配及排序操作;

索引分类

在MySQL数据库,将索引的具体类型主要分为以下几类:主键索引、唯一索引、常规索引、全文索引。

分类 含义 特点 关键字
主键索引 针对于表中主键创建的索引 默认自动创建,只能有一个 PRIMARY
唯一索引 避免同一个表中某数据列中的值重复 可以有多个 UNIQUE
常规索引 快速定位特定数据 可以有多个
全文索引 全文索引查找的是文本中的关键词,而不是比较索引中的值 可以有多个 FULLTEXT

聚集索引&二级索引

而在在InnoDB存储引擎中,根据索引的存储形式,又可以分为以下两种:

分类 含义 特点
聚集索引(ClusteredIndex) 将数据存储与索引放到了一块,索引结构的叶子节点保存了行数据 必须有,而且只有一个
二级索引(SecondaryIndex) 将数据与索引分开存储,索引结构的叶子节点关联的是对应的主键 可以存在多个

聚集索引选取规则:

如果存在主键,主键索引就是聚集索引。

如果不存在主键,将使用第一个唯一(UNIQUE)索引作为聚集索引。

如果表没有主键,或没有合适的唯一索引,则InnoDB会自动生成一个rowid作为隐藏的聚集索引。

MySQL进阶学习_第12张图片

 聚集索引的叶子节点下挂的是这一行的数据。

二级索引的叶子节点下挂的是该字段值对应的主键值。

具体过程如下:

①.由于是根据name字段进行查询,所以先根据name='Arm'到name字段的二级索引中进行匹配查找。但是在二级索引中只能查找到Arm对应的主键值10。(根据排序 先找Lee,A在L之前,继续向左子节点找到Geek,A在G之前,继续向左子节点找到Arm,匹配上,找到Arm对应的主键值10)

②.由于查询返回的数据是*,所以此时,还需要根据主键值10,到聚集索引中查找10对应的记录,最终找到10对应的行row。

③.最终拿到这一行的数据,直接返回即可。

回表查询:这种先到二级索引中查找数据,找到主键值,然后再到聚集索引中根据主键值,获取数据的方式,就称之为回表查询。

面试题:

以下两条SQL语句,那个执行效率高?为什么?

A. select * from user where id = 10 ;

B. select * from user where name = 'Arm' ;

备注:id为主键,name字段创建的有索引;

解答:A语句的执行性能要高于B语句。因为A语句直接走聚集索引,直接返回数据。而B语句需要先查询name字段的二级索引,然后再查询聚集索引,也就是需要进行回表查询。

面试题:

InnoDB主键索引的B+tree高度为多高呢?

假设:一行数据大小为1k,一页中可以存储16行这样的数据。

InnoDB的指针占用6个字节的空间,主键即使为bigint,占用字节数为8。

高度为2:n * 8 + (n + 1) * 6 = 16*1024 ,算出n约为1170

1171* 16 = 18736

也就是说,如果树的高度为2,则可以存储18000多条记录。

高度为3:

1171 * 1171 * 16 = 21939856

也就是说,如果树的高度为3,则可以存储2200w左右的记录。

索引语法

1).创建索引

CREATE [ UNIQUE | FULLTEXT ] INDEX index_name ON table_name (index_col_name,...);

2).查看索引

SHOW INDEX FROM table_name;

3).删除索引

DROP INDEX index_name ON table_name;

先来创建一张表tb_user

create table tb_user
(
    id int primary key auto_increment comment ' 主键 ', 
    name varchar(50) not null comment ' 用户名 ',
    phone varchar(11) not null comment ' 手机号 ',
    email varchar(100) comment ' 邮箱 ',
    profession varchar(11) comment ' 专业 ',
    age tinyint unsigned comment ' 年龄 ',
    gender char(1) comment ' 性别 , 1 : 男 , 2 : 女 ',
    status char(1) comment ' 状态 ',
    createtime datetime comment ' 创建时间 '
) comment
        ' 系统用户表 '
;

A. name字段为姓名字段,该字段的值可能会重复,为该字段创建索引。

CREATE INDEX idx_user_name ON tb_user (name);

B. phone手机号字段的值,是非空,且唯一的,为该字段创建唯一索引。

CREATE UNIQUE INDEX idx_user_phone ON tb_user (phone);

C.为profession、age、status创建联合索引。

CREATE INDEX idx_user_pro_age_sta ON tb_user (profession,age,status);

D.为email建立合适的索引来提升查询效率。

CREATE INDEX idx_email ON tb_user (email);

SQL性能分析

SQL执行频率

MySQL客户端连接成功后,通过show [session|global] status命令可以提供服务器状态信息。通过如下指令,可以查看当前数据库的INSERT、UPDATE、DELETE、SELECT的访问频次:

show session | global status

MySQL进阶学习_第13张图片

通过上述指令,我们可以查看到当前数据库到底是以查询为主,还是以增删改为主,从而为数据库优化提供参考依据。如果是以增删改为主,我们可以考虑不对其进行索引的优化。如果是以查询为主,那么就要考虑对数据库的索引进行优化了。

慢查询日志

慢查询日志记录了所有执行时间超过指定参数(long_query_time,单位:秒,默认10秒)的所有SQL语句的日志。

MySQL的慢查询日志默认没有开启,我们可以查看一下系统变量slow_query_log

show variables like 'slow_query_log';

 如果要开启慢查询日志,需要在MySQL的配置文件(/etc/my.cnf)中配置如下信息:

#开启MySQL慢日志查询开关

slow_query_log=1

#设置慢日志的时间为2秒,SQL语句执行时间超过2秒,就会视为慢查询,记录慢查询日志long_query_time=2

profile详情

show profiles能够在做SQL优化时帮助我们了解时间都耗费到哪里去了。通过have_profiling参数,能够看到当前MySQL是否支持profile操作:

select @@have_profiling;

MySQL进阶学习_第14张图片

 可以看到,当前MySQL是支持profile操作的,但是开关是关闭的。可以通过set语句在session/global级别开启profiling:

SET profiling = 1;

查看指令的执行耗时:

--查看每一条SQL的耗时基本情况

show profiles;

--查看指定query_id的SQL语句各个阶段的耗时情况

show profile for query query_id;

--查看指定query_id的SQL语句CPU的使用情况

show profile cpu for query query_id;

explain

EXPLAIN 或者 DESC 命令获取MySQL如何执行SELECT语句的信息,包括在SELECT语句执行过程中表如何连接和连接的顺序。

--直接在select语句之前加上关键字 explain / desc

EXPLAIN SELECT 字段列表 FROM 表名 WHERE 条件;

Explain执行计划中各个字段的含义:

字段 含义
id select查询的序列号,表示查询中执行select子句或者是操作表的顺序(id相同,执行顺序从上到下;id不同,值越大,越先执行)。
select_type 表示SELECT的类型,常见的取值有SIMPLE(简单表,即不使用表连接或者子查询)、PRIMARY(主查询,即外层的查询)、UNION(UNION中的第二个或者后面的查询语句)、SUBQUERY(SELECT/WHERE之后包含了子查询)等
type 表示连接类型,性能由好到差的连接类型为NULL、system、const、eq_ref、ref、range、index、all。
possible_key 显示可能应用在这张表上的索引,一个或多个。
key 实际使用的索引,如果为NULL,则没有使用索引。
key_len
表示索引中使用的字节数,该值为索引字段最大可能长度,并非实际使用长度,在不损失精确性的前提下,长度越短越好。
rows MySQL认为必须要执行查询的行数,在innodb引擎的表中,是一个估计值,可能并不总是准确的。
filtered 表示返回结果的行数占需读取行数的百分比,filtered的值越大越好。

索引使用

验证索引效率

1000w条数据的表 查询带索引的主键id

 这张表中id为主键,有主键索引,而其他字段是没有建立索引的。

 select * from tb_sku where id = 1\G;

MySQL进阶学习_第15张图片

 可以看到即使有1000w的数据,根据id进行数据查询,性能依然很快,因为主键id是有索引的。那么接下来,我们再来根据sn字段进行查询,执行如下SQL:

SELECT * FROM tb_sku WHERE sn = ' 1 00000003145001' ;

MySQL进阶学习_第16张图片

 create index idx_sku_sn on tb_sku(sn) ;

然后再次执行相同的SQL语句,再次查看SQL的耗时。

MySQL进阶学习_第17张图片

 最左前缀法则

 如果索引了多列(联合索引),要遵守最左前缀法则。最左前缀法则指的是查询从索引的最左列开始,并且不跳过索引中的列。如果跳跃某一列,索引将会部分失效(后面的字段索引失效)。

注意:最左前缀法则中指的最左边的列,是指在查询时,联合索引的最左边的字段(即是第一个字段)必须存在,与我们编写SQL时,条件编写的先后顺序无关。

范围查询

联合索引中,出现范围查询(>,<),范围查询右侧的列索引失效。

在业务允许的情况下,尽可能的使用类似于>=或<=这类的范围查询,而避免使用>或<

索引失效情况

索引列运算

不要在索引列上进行运算操作,索引将失效。

A.当根据phone字段进行等值匹配查询时,索引生效。

explain select * from tb_user where phone = '17799990015';  索引生效

B.当根据phone字段进行函数运算操作之后,索引失效。

explain select * from tb_user where substring (phone,10,2) = '15'; 索引失效

字符串不加引号

字符串类型字段使用时,不加引号,索引将失效。

explain select * from tb_user where profession = '软件工程' and age = 31 and status = '0';

索引生效

explain select * from tb_user where profession = '软件工程' and age = 31 and status = 0;

索引失效

经过上面两组示例,我们会明显的发现,如果字符串不加单引号,对于查询结果,没什么影响,但是数据库存在隐式类型转换,索引将失效。

模糊查询

如果仅仅是尾部模糊匹配,索引不会失效。如果是头部模糊匹配,索引失效。

explains elect * from tb_user where profession like '软件%';索引生效

explains elect * from tb_user where profession like '%软件';索引失效

explains elect * from tb_user where profession like '%软件%';索引失效

由于上面查询语句中,都是根据profession字段查询,符合最左前缀法则,联合索引是可以生效的,我们主要看一下,模糊查询时,%加在关键字之前,和加在关键字之后的影响。

经过上述的测试,我们发现,在like模糊查询中,在关键字后面加%,索引可以生效。而如果在关键字前面加了%,索引将会失效

or连接条件

用or分割开的条件,如果or前的条件中的列有索引,而后面的列中没有索引,那么涉及的索引都不会被用到。 只有or两侧的列都有索引,索引才会生效

数据分布影响

如果MySQL评估使用索引比全表更慢,则不使用索引。

就是因为MySQL在查询时,会评估使用索引的效率与走全表扫描的效率,如果走全表扫描更快,则放弃索引,走全表扫描。因为索引是用来索引少量数据的,如果通过索引查询返回大批量的数据,则还不如走全表扫描来的快,此时索引就会失效。

1).use index:建议MySQL使用哪一个索引完成此次查询(仅仅是建议,mysql内部还会再次进行评估)。

explain select * from tb_user use index (idx_user_pro) where profession = '软件工程';

2).ignore index:忽略指定的索引。

explain select * from tb_user ignore index (idx_user_pro) where profession = '软件工程';

3).force index:强制使用索引。

explain select * from tb_user force index (idx_user_pro) where profession = '软件工程';

面试题:

一张表, 有四个字段(id, username, password, status), 由于数据量大, 需要对 以下SQL语句进行优化, 该如何进行才是最优方案:

select id,username,password from tb_user where username = 'itcast';

答案: 针对于 username, password建立联合索引, sql为:

create index idx_user_name_pass on tb_user(username,password);

这样可以避免上述的SQL语句,在查询的过程中,出现回表查询。

前缀索引

当字段类型为字符串(varchar,text,longtext等)时,有时候需要索引很长的字符串,这会让 索引变得很大,查询时,浪费大量的磁盘IO, 影响查询效率。此时可以只将字符串的一部分前缀,建 立索引,这样可以大大节约索引空间,从而提高索引效率。

1). 语法

create index idx_xxxx on table_name(column(n)) ;

2). 前缀长度

可以根据索引的选择性来决定,而选择性是指不重复的索引值(基数)和数据表的记录总数的比值, 索引选择性越高则查询效率越高, 唯一索引的选择性是1,这是最好的索引选择性,性能也是最好的。

MySQL进阶学习_第18张图片

 单列索引与联合索引

单列索引:即一个索引只包含单个列。

联合索引:即一个索引包含了多个列。

在业务场景中,如果存在多个查询条件,考虑针对于查询字段建立索引时,建议建立联合索引, 而非单列索引。

MySQL进阶学习_第19张图片

索引设计原则 

1). 针对于数据量较大,且查询比较频繁的表建立索引。

2). 针对于常作为查询条件(where)、排序(order by)、分组(group by)操作的字段建立索 引。

3). 尽量选择区分度高的列作为索引,尽量建立唯一索引,区分度越高,使用索引的效率越高。

4). 如果是字符串类型的字段,字段的长度较长,可以针对于字段的特点,建立前缀索引。 5). 尽量使用联合索引,减少单列索引,查询时,联合索引很多时候可以覆盖索引,节省存储空间, 避免回表,提高查询效率。

6). 要控制索引的数量,索引并不是多多益善,索引越多,维护索引结构的代价也就越大,会影响增 删改的效率。

7). 如果索引列不能存储NULL值,请在创建表时使用NOT NULL约束它。当优化器知道每列是否包含 NULL值时,它可以更好地确定哪个索引最有效地用于查询。

SQL优化

插入数据

insert

如果我们需要一次性往数据库表中插入多条记录,可以从以下三个方面进行优化。

1). 优化方案一

批量插入数据

Insert into tb_test values(1,'Tom'),(2,'Cat'),(3,'Jerry');

2). 优化方案二

手动控制事务

start transaction;

insert into tb_test values(1,'Tom'),(2,'Cat'),(3,'Jerry');

insert into tb_test values(4,'Tom'),(5,'Cat'),(6,'Jerry');

insert into tb_test values(7,'Tom'),(8,'Cat'),(9,'Jerry');

commit;

3). 优化方案三

主键顺序插入,性能要高于乱序插入。

主键乱序插入 : 8 1 9 21 88 2 4 15 89 5 7 3

主键顺序插入 : 1 2 3 4 5 7 8 9 15 21 88 89

大批量插入数据

如果一次性需要插入大批量数据(比如: 几百万的记录),使用insert语句插入性能较低,此时可以使 用MySQL数据库提供的load指令进行插入。

可以执行如下指令,将数据脚本文件中的数据加载到表结构中:

-- 客户端连接服务端时,加上参数 -–local-infile

mysql –-local-infile -u root -p

-- 设置全局参数local_infile为1,开启从本地加载文件导入数据的开关

set global local_infile = 1;

-- 执行load指令将准备好的数据,加载到表结构中

load data local infile '/root/sql1.log' into table tb_user fields terminated by ',' lines terminated by '\n' ;

主键顺序插入性能高于乱序插入

主键优化

索引设计原则 满足业务需求的情况下,尽量降低主键的长度。

插入数据时,尽量选择顺序插入,选择使用AUTO_INCREMENT自增主键。

尽量不要使用UUID做主键或者是其他自然主键,如身份证号。

业务操作时,避免对主键的修改。

order by优化

MySQL的排序,有两种方式:

Using filesort : 通过表的索引或全表扫描,读取满足条件的数据行,然后在排序缓冲区sort buffer中完成排序操作,所有不是通过索引直接返回排序结果的排序都叫 FileSort 排序。

Using index : 通过有序索引顺序扫描直接返回有序数据,这种情况即为 using index,不需要 额外排序,操作效率高。

对于以上的两种排序方式,Using index的性能高,而Using filesort的性能低,我们在优化排序 操作时,尽量要优化为 Using index。

为在MySQL中我们创建的索引,默认索引的叶子节点是从小到大排序的,而此时我们查询排序 时,是从大到小,所以,在扫描时,就是反向扫描,就会出现 Backward index scan。 在 MySQL8版本中,支持降序索引,我们也可以创建降序索引。

order by优化原则:

A. 根据排序字段建立合适的索引,多字段排序时,也遵循最左前缀法则。

B. 尽量使用覆盖索引。

C. 多字段排序, 一个升序一个降序,此时需要注意联合索引在创建时的规则(ASC/DESC)。

D. 如果不可避免的出现filesort,大数据量排序时,可以适当增大排序缓冲区大小 sort_buffer_size(默认256k)。

group by优化

A. 在分组操作时,可以通过索引来提高效率。

B. 分组操作时,索引的使用也是满足最左前缀法则的。

limit优化

优化思路: 一般分页查询时,通过创建 覆盖索引 能够比较好地提高性能,可以通过覆盖索引加子查 询形式进行优化。

select * from tb_sku limit 9000000,10;

explain select * from tb_sku t , (select id from tb_sku order by id limit 2000000,10) a where t.id = a.id;   

count优化

 count用法

count() 是一个聚合函数,对于返回的结果集,一行行地判断,如果 count 函数的参数不是 NULL,累计值就加 1,否则不加,最后返回累计值。 用法:count(*)、count(主键)、count(字段)、count(数字)

count用法 含义
count(主键) InnoDB 引擎会遍历整张表,把每一行的 主键id 值都取出来,返回给服务层。 服务层拿到主键后,直接按行进行累加(主键不可能为null)
count(字段) 没有not null 约束 : InnoDB 引擎会遍历整张表把每一行的字段值都取出 来,返回给服务层,服务层判断是否为null,不为null,计数累加。 有not null 约束:InnoDB 引擎会遍历整张表把每一行的字段值都取出来,返 回给服务层,直接按行进行累加。
count(数字) InnoDB 引擎遍历整张表,但不取值。服务层对于返回的每一行,放一个数字“1” 进去,直接按行进行累加。
count(*) InnoDB引擎并不会把全部字段取出来,而是专门做了优化,不取值,服务层直接 按行进行累加。

按照效率排序的话,count(字段) < count(主键 id) < count(1) ≈ count(*),所以尽量使用 count(*)

update优化

我们主要需要注意一下update语句执行时的注意事项。

update course set name = 'javaEE' where id = 1 ;

当我们在执行删除的SQL语句时,会锁定id为1这一行的数据,然后事务提交之后,行锁释放。

但是当我们在执行如下SQL时。

update course set name = 'SpringBoot' where name = 'PHP'

当我们开启多个事务,在执行上述的SQL时,我们发现行锁升级为了表锁。 导致该update语句的性能 大大降低。

InnoDB的行锁是针对索引加的锁,不是针对记录加的锁 ,并且该索引不能失效,否则会从行锁升级为表锁,会导致并发性能降低

优化:对name字段加上索引,在sql语句中注意索引失效的问题

总结:

1.插入数据

insert:批量插入 手动控制事务 主键顺序插入  大批量数据插入:load data local infile

2.主键优化

主键长度尽量短 顺序插入 尽量使用主键自增 避免使用UUID等

3.order by优化

using index:直接通过索引返回数据,性能高

using filesort:需要将返回的结果在排序缓冲区排序

4.group by优化

索引,多字段分组满足最左前缀法则

5.limit优化

覆盖索引+子查询

6.count优化

count(字段)

7.update优化

尽量根据主键/索引字段进行数据更新

视图

视图(View)是一种虚拟存在的表。视图中的数据并不在数据库中实际存在,行和列数据来自定义视 图的查询中使用的表,并且是在使用视图时动态生成的。 通俗的讲,视图只保存了查询的SQL逻辑,不保存查询结果。所以我们在创建视图的时候,主要的工作 就落在创建这条SQL查询语句上。

语法

1). 创建

CREATE [OR REPLACE] VIEW 视图名称[(列名列表)] AS SELECT语句 [ WITH [ CASCADED | LOCAL ] CHECK OPTION ]

2). 查询

查看创建视图语句:SHOW CREATE VIEW 视图名称;

查看视图数据:SELECT * FROM 视图名称 ...... ;

3). 修改

方式一:CREATE [OR REPLACE] VIEW 视图名称[(列名列表)] AS SELECT语句 [ WITH [ CASCADED | LOCAL ] CHECK OPTION ]

方式二:ALTER VIEW 视图名称[(列名列表)] AS SELECT语句 [ WITH [ CASCADED | LOCAL ] CHECK OPTION ]

4). 删除

DROP VIEW [IF EXISTS] 视图名称 [,视图名称] ...

演示示例:

-- 创建视图

create or replace view stu_v_1 as select id,name from student where id <= 10;

-- 查询视图

show create view stu_v_1;

select * from stu_v_1;

select * from stu_v_1 where id < 3;

 -- 修改视图

create or replace view stu_v_1 as select id,name,no from student where id <= 10;

alter view stu_v_1 as select id,name from student where id <= 10;

-- 删除视图

drop view if exists stu_v_1;

检查选项:

当使用WITH CHECK OPTION子句创建视图时,MySQL会通过视图检查正在更改的每个行,例如 插 入,更新,删除,以使其符合视图的定义。 MySQL允许基于另一个视图创建视图,它还会检查依赖视 图中的规则以保持一致性。为了确定检查的范围,mysql提供了两个选项: CASCADED 和 LOCAL ,默认值为 CASCADED 。

1). CASCADED  级联。

比如,v2视图是基于v1视图的,如果在v2视图创建的时候指定了检查选项为 cascaded,但是v1视图 创建时未指定检查选项。 则在执行检查时,不仅会检查v2,还会级联检查v2的关联视图v1。

MySQL进阶学习_第20张图片

2). LOCAL  本地。

 比如,v2视图是基于v1视图的,如果在v2视图创建的时候指定了检查选项为 local ,但是v1视图创 建时未指定检查选项。 则在执行检查时,知会检查v2,不会检查v2的关联视图v1。

MySQL进阶学习_第21张图片

视图的更新

要使视图可更新,视图中的行与基础表中的行之间必须存在一对一的关系。如果视图包含以下任何一 项,则该视图不可更新:

A. 聚合函数或窗口函数(SUM()、 MIN()、 MAX()、 COUNT()等)

B. DISTINCT

C. GROUP BY

D. HAVING

E. UNION 或者 UNION ALL

视图作用

1). 简单

视图不仅可以简化用户对数据的理解,也可以简化他们的操作。那些被经常使用的查询可以被定义为视 图,从而使得用户不必为以后的操作每次指定全部的条件。

2). 安全

数据库可以授权,但不能授权到数据库特定行和特定的列上。通过视图用户只能查询和修改他们所能见 到的数据

3). 数据独立

视图可帮助用户屏蔽真实表结构变化带来的影响。

案例

1). 为了保证数据库表的安全性,开发人员在操作tb_user表时,只能看到的用户的基本字段,屏蔽 手机号和邮箱两个字段。

create view tb_user_view as select id,name,profession,age,gender,status,createtime from tb_user;

select * from tb_user_view;

2). 查询每个学生所选修的课程(三张表联查),这个功能在很多的业务中都有使用到,为了简化操 作,定义一个视图。

create view tb_stu_course_view as select s.name student_name , s.no student_no , c.name course_name from student s, student_course sc , course c where s.id = sc.studentid and sc.courseid = c.id;

select * from tb_stu_course_view;

你可能感兴趣的:(mysql,sql)