Memory 存储引擎
Memory 存储引擎将表中的数据存放在内存中,非常适合存储临时数据的临时表,Memory 默认的存储引擎是哈希索引,而不是我们熟悉的 B+ 树。Memory 存储引擎的速度非常快,Mysql 使用 Memory 作为临时表来存放查询的中间结果。
Merge 存储引擎
Merge存储引擎是一组MyISAM表的组合,这些MyISAM表必须结构完全相同,merge表本身并没有数据,对merge类型的表可以进行查询,更新,删除操作,这些操作实际上是对内部的MyISAM表进行的。
聚集索引和非聚集索引的根本区别是表记录的排列顺序与索引的排列顺序是否一致。
聚集索引表记录的排列顺序与索引的排列顺序一致
非聚集索引指定了表中记录的逻辑顺序,但记录的物理顺序和索引的顺序不一致。聚集索引和非聚集索引都采用了B+树的结构,但非聚集索引的叶子层并不与实际的数据页相重叠,而采用叶子层包含一个指向表中的记录在数据页中的指针的方式。
聚集索引确定表中数据的物理顺序。
非聚集索引中,数据存储在一个地方,索引存储在另一个地方,索引带有指针指向数据的存储位置。
聚集索引的顺序就是数据的物理存储顺序,而非聚集索引的顺序和数据物理排列无关。因为数据在物理存放时只能有一种排列方式,所以一个表只能有一个聚集索引。在SQL SERVER中,索引是通过二叉树的数据结构来描述的;我们可以如此理解这个两种索引:聚集索引的叶节点就是数据节点,而非聚集索引的叶节点仍然是索引节点,只不过其包含一个指向对应数据块的指针。
Mysql 数据库索引的类型
Mysql 数据库索引种类
1. 未提交读
事务中的修改,即使没有提交,对其它事务也是可见的。
2. 提交读
一个事务只能读取已经提交的事务所做的修改。换句话说,一个事务所做的修改在提交之前对其它事务是不可见的。
3. 可重复读
保证在同一个事务中多次读取同样数据的结果是一样的。
4. 可串行化
强制事务串行执行。
多版本并发控制(Multi-Version Concurrency Control,MVCC)是 MySQL 的 InnoDB 实现隔离级别的一种具体方法,用于实现提交读和可重复读两种隔离级别。而未提交读隔离级别总是读取最新的数据行,无需使用 MVCC。可串行化隔离级别需要对所有读取的行都加锁,单纯使用 MVCC 无法实现。
mysql联合索引
联合索引又叫复合索引,对于联合索引,Mysql 从左到右的使用索引中的字段,一个查询可以只使用索引中的一部份,但只能是最左侧部分。
例如索引是key index (a,b,c). 可以支持a | a,b| a,b,c 3种组合进行查找,但不支持 b,c进行查找 .当最左侧字段是常量引用时,索引就十分有效。
如:建立 姓名(name)、年龄(age)、性别(sex)的复合索引。
select * from user where name=’zhangsan’ and age = ‘1’; 使用到索引
select * from user where age=’1’ and sex=’男’;不使用索引
联合索引和单个索引的区别:
如果我们创建了(area, age,salary)的复合索引,那么其实相当于创建了:
(area,age,salary),(area,age)、(area)三个索引,这被称为最佳左前缀
特性。因此我们在创建复合索引时应该将最常用作限制条件的列放在最左边,依次递减。
例:
联合索引和单个索引的区别:
如果我们创建了(area, age,salary)的复合索引,那么其实相当于创建了:
(area,age,salary),(area,age)、(area)三个索引,这被称为最佳左前缀
特性。因此我们在创建复合索引时应该将最常用作限制条件的列放在最左边,依次递减。
例:
select * from test where area='11'
select * from test where area='11' and age=1
select * from test where area='11' and age=1 and salary=2.0
以上有索引
select * from test where age=11
select * from test where age=1 and salary=2.0
以上无索引
-----------------------------------
如果在查询中需要匹配多个字段的条件,可以把这几个字段做个联合索引,效率要比在每个字段上加索引高多了
以上有索引
select * from test where age=11
select * from test where age=1 and salary=2.0
以上无索引
为什么
存储过程(Stored Procedure)是一种在数据库中存储复杂程序,以便外部程序调用的一种数据库对象。存储过程是为了完成特定功能的SQL语句集,经编译创建并保存在数据库中,用户可通过指定存储过程的名字并给定参数(需要时)来调用执行。存储过程思想上很简单,就是数据库 SQL 语言层面的代码封装与重用。
视图(子查询):是从一个或多个表导出的虚拟表,其内容由查询定义。具有普通表的结构,但是不实现数据存储。视图是从一个或几个基本表(或视图)导出的表。它与基本表不同,是一个虚表。数据库只存放视图的定义,而不存放视图对应的数据,这些数据仍存放在原来的基本表中。所以基本表中的数据发生变化,从视图中查询出的数据也就随之改变了。从这个意义上讲,视图就像一个窗口,透过它可以看到数据库中自己感兴趣的数据及其变化。
通常,视图是可以更新的(即,可以对它们使用 INSERT 、 UPDATE 和 DELETE )。更新一个视图将更新其基表(可以回忆一下,视图本身没有数据)。如果你对视图增加或删除行,实际上是对其基表增加或删除行。
作用:
(1)简化了操作,把经常使用的数据定义为视图。
(2)安全性,用户只能查看和修改能看到的数据。
(3)逻辑上独立,屏蔽了真实表的结构带来的影响。
分库分表
关系型数据库本身比较容易成为系统瓶颈,单机存储容量、连接数、处理能力都有限。当单表的数据量达到1000W或100G以后,由于查询维度较多,即使添加从库、优化索引,做很多操作时性能仍下降严重。此时就要考虑对其进行切分了,切分的目的就在于减少数据库的负担,缩短查询时间。
数据库分布式的核心内容无非就是数据切分(sharding),以及切分后对数据的定位、整合。数据切分就是将数据分散存储到多个数据库中,使得单一数据库中的数据量变小,通过扩充主机的数量缓解单一数据库的性能问题,从而达到提升数据库操作性能的目的。数据切分根据其切分类型,可以分为两种方式:垂直(纵向)切分和水平(横向)切分。
垂直切分常见有垂直分库和垂直分表两种。
垂直分库就是根据业务耦合性,将关联度低的不同表存储在不同的数据库。做法与大系统拆分为多个小系统类似,按业务分类进行独立划分。与"微服务治理"的做法相似,每个微服务使用单独的一个数据库。如图:
垂直分表是基于数据库中的"列"进行,某个表字段较多,可以新建一张扩展表,将不经常用或字段长度较大的字段拆分出去到扩展表中。在字段很多的情况下(例如一个大表有100多个字段),通过"大表拆小表",更便于开发与维护,也能避免跨页问题,MySQL底层是通过数据页存储的,一条记录占用空间过大会导致跨页,造成额外的性能开销。另外数据库以行为单位将数据加载到内存中,这样表中字段长度较短且访问频率较高,内存能加载更多的数据,命中率更高,减少了磁盘IO,从而提升了数据库性能。
垂直切分的优点:
缺点:
当一个应用难以再细粒度的垂直切分,或切分后数据量行数巨大,存在单库读写、存储性能瓶颈,这时候就需要进行水平切分了。
水平切分分为库内分表和分库分表,是根据数据库内在的逻辑关系,将同一个表按不同条件分散到多个数据库或多个表中,每个表中只包含一部分数据,从而使得单个表的数据量变小,达到分布式的效果。如图所示:
库内分表只解决了单一表数据量过大的问题,但没有将表分布到不同机器的库上,因此对于减轻MySQL数据库的压力来说,帮助不是很大,大家还是竞争同一个物理机的CPU、内存、网络IO,最好通过分库分表来解决。
水平切分的优点:
缺点:
原因1:
like本身效率就比较低,应该尽量避免查询条件使用like。
对于like ‘%…%’(全模糊)这样的条件,是无法使用索引的,全表扫描自然效率很低
由于匹配算法的关系,模糊查询的字段长度越大,模糊查询效率越低
解决办法:
首先尽量避免模糊查询,如果因为业务需要一定要使用模糊查询,则至少保证不要使用全模糊查询,对于右模糊查询,即like ‘…%’,是会使用索引的;左模糊like‘%…’无法直接使用索引
原因2:
or 语句使用不当会引起全表扫描
where子句中比较的两个条件,一个有索引,一个没索引,使用or则会引起全表扫描。
原因3:
查询条件中使用了不等于操作符(<>、!=)的select语句执行慢
SQL中,不等于操作符会限制索引,引起全表扫描,即使比较的字段上有索引
原因4:
查询条件中含有is null的select语句执行慢,如: select id from t where num is null
不能用null作索引,任何包含null值的列都将不会被包含在索引中。即使索引有多列这样的情况下,只要这些列中有一列含有null,该列 就会从索引中排除。也就是说如果某列存在空值,即使对该列建索引也不会提高性能。 任何在where子句中使用is null或is not null的语句优化器是不允许使用索引的。
原因5:
in 和 not in 也要慎用,否则会导致全表扫描
主要涉及三个线程:binlog 线程、I/O 线程 和 SQL 线程
主服务器处理写操作以及实时性要求比较高的读操作,而从服务器处理读操作。
读写分离能提高性能的原因在于:
读写分离常用代理方式来实现,代理服务器接收应用层传来的读写请求,然后决定转发到哪个服务器
优化数据访问
分解大连接查询
如分解成多个单表查询
乐观锁相对悲观锁而言,它认为数据一般情况下不会造成冲突。所以在数据进行提交更新的时候,才会正式对数据的冲突与否进行检测,如果发现冲突了,则返回错误信息,让用户决定如何去做。
利用数据版本号(version)机制是乐观锁最常用的一种实现方式。一般通过为数据库表增加一个数字类型的 “version” 字段,当读取数据时,将version字段的值一同读出,数据每更新一次,对此 version 值+1。当我们提交更新的时候,使用数据库表对应记录的当前版本信息与第一次取出来的version值进行比对,如果数据库表当前版本号与第一次取出来的version值相等,则予以更新,否则认为是过期数据,返回更新失败。
悲观锁(Pessimistic Locking),悲观锁是指在数据处理过程,使数据处于锁定状态,一般使用数据库的锁机制实现。
悲观锁并不是适用于任何场景,它也存在一些不足,因为悲观锁大多数情况下依靠数据库的锁机制实现,以保证操作最大程度的独占性。如果加锁的时间过长,其他用户长时间无法访问,影响了程序的并发访问性,同时这样对数据库性能开销影响也很大,特别是对长事务而言,这样的开销往往无法承受,这时就需要乐观锁。
数据库事务是数据库执行过程中的一个逻辑单位,一个事务通常包含了对数据库的读/写操作。它的存在包含有以下两个目的:
共享锁又叫读锁,如果事务 T1 对行 R 加上 S 锁,则
排它锁又叫写锁,如果事务T1对行R加上X锁,则
举个例子:
事务A锁住了表中的一行,让这一行只能读,不能写。
之后,事务B申请整个表的写锁。
如果事务B申请成功,那么理论上它就能修改表中的任意一行,这与A持有的行锁是冲突的。
数据库为了避免这种冲突,就是说要让B的申请被阻塞,直到 A 释放行锁。
数据库怎么判断这个冲突呢?
step1:判断表是否已被其他事务用表锁锁表
step2:判断表中的每一行是否已被行锁锁住
注意step2中通过遍历查询,这样的判断方法效率实在不高,因为需要遍历整个表,于是就有了意向锁。
在意向锁存在的情况下,事务A必须先申请表的意向共享锁,成功后再申请一行的行锁。
在意向锁存在的情况下,上面的判断可以改成
step1:不变
step2:发现表上有意向共享锁,说明表中有些行被共享行锁锁住了,因此,事务B申请表的写锁会被阻塞。
间隙锁
什么是间隙锁?
当我们用范围条件而不是相等条件检索数据,并请求共享或排他锁时,InnoDB会给符合条件的已有数据记录的索引项加锁;对于键值在条件范围内但不存在的记录,叫做“间隙(GAP)”,InnoDB也会对这个“间隙”加锁,这种锁机制就是所谓的间隙锁(NEXT-KEY)锁。
间隙锁的作用
保证某个间隙内的数据在锁定情况下不会发生任何变化。