MySQL

文章目录

  • 1.数据库的基本概念
    • 1.1名称解释
      • 实体
      • 属性
      • 元组
      • < font color=red> 分量
      • 全码
      • 主属性,非主属性, 外码
    • 1.2 范式
      • 第一范式
      • 第二范式
      • 第三范式
      • BC范式(BCNF)
      • 范式总结
  • 2.数据库的一些基本操作
    • 2.1 基本操作(创建,删除,增删改查)
      • 数据库操作
      • 表操作
      • 基本表操作(增删改查等)
      • 高级的操作
      • 例子
  • 3.MySQL总体认识
    • 3.1MySQL总体结构
      • Mysq架构图
      • Mysql的物理文件组成
      • Mysql存储引擎概述
      • Mysql工具
    • 3.2 权限管理与安全
      • 3.2.1 权限表
      • 3.2.2.创建用户
      • 3.2.3.删除用户
      • 3.2.4 修改密码
      • 3.2.5 权限管理
      • 3.2.6 访问控制
      • 3.2.7 Mysql中的安全问题
    • 3.3 数据备份与还原
      • 3.3.1 数据库备份
      • 3.3.2 mysqldump中的一些参数
      • 3.3.3.数据还原
      • 3.3. 4.数据库迁移
      • 3.3. 5.表的的导入导出
    • 3.4 高级特性
      • 3.4.1.查询缓存
      • 3.4. 2.合并表和分区表
      • 3.4. 3.事务控制
      • 3.4.4.分布式事务
    • 3.5 锁
      • 3.5. 1.锁机制概述
      • 3.5. 2.MyIsam表锁
      • 3.5. 对于MyISAM表锁的一些优化:
      • 3.5. 3.InnoDB行锁
      • 3.5.4.关于间隙锁
      • 3.5. 5.innoDB行锁优化
    • 3.6 性能优化
      • 3.6.1 优化简介
      • 3.6.2.Mysql query optimizer概述
      • 3.6. 3.利用Explain分析查询语句
      • 3.6. 4.合理使用索引优化查询
      • 3.6. 5.不同类型的sql语句优化
      • 3.6.6.优化数据库结构
      • 3.6. 7.分析表,检查表,优化表
      • 3.6. 8 服务器配置优化
      • 3.6. 9 并发设置
      • 3.6. 10 线程优化
      • 3.6. 11关于临时表的优化
      • 3.6. 12 关于mysql replication
      • 3.6. 13 服务器启动参数(和复制相关的)
      • 3.6. 14 切换主从服务器
      • 3.6. 15 mysql cluster
  • 4.MySQL的一些操作
  • 5.其他
    • 5.1字符编码问题
      • 查看数据库字符编码:
      • 修改字符编码
    • 5.2 SQL执行顺序问题
      • sql语句的执行步骤:
      • SQL Select语句完整的执行顺序:
    • 5.3 MySQL内存的使用说明(全局缓存+线程缓存)
      • 全局缓存
      • 线程缓存
    • 5.4 Innodb
      • 5.4.1、插入缓冲(insert buffer)的原理:
      • 5.4.2 两次写(double write)
      • 自适应哈希索引(adaptive hash index)

1.数据库的基本概念

1.1名称解释

实体

现实世界中客观存在并可以被区别的事物。比如“一个学生”、“一本书”、“一门课”等等。值得强调的是这里所说的“事物”不仅仅是看得见摸得着的“东西”,它也可以是虚拟的,不如说“老师与学校的关系”。

属性

教科书上解释为:“实体所具有的某一特性”,由此可见,属性一开始是个逻辑概念,比如说,“性别”是“人”的一个属性。在关系数据库中,属性又是个物理概念,属性可以看作是“表的一列”。

元组

表中的一行就是一个元组。

< font color=red> 分量

元组的某个属性值。在一个关系数据库中,它是一个操作原子,即关系数据库在做任何操作的时候,属性是“不可分的”。否则就不是关系数据库了。

表中可以唯一确定一个元组的某个属性(或者属性组),如果这样的码有不止一个,那么大家都叫候选码,我们从候选码中挑一个出来做老大,它就叫主码。

全码

如果一个码包含了所有的属性,这个码就是全码。

主属性,非主属性, 外码

主属性:一个属性只要在任何一个候选码中出现过,这个属性就是主属性。

非主属性:与上面相反,没有在任何候选码中出现过,这个属性就是非主属性。
外码:一个属性(或属性组),它不是码,但是它别的表的码,它就是外码。

1.2 范式

第一范式

定义:如果关系R 中所有属性的值域都是单纯域,那么关系模式R是第一范式的
那么符合第一模式的特点就有
1)有主关键字
2)主键不能为空,
3)主键不能重复
4)字段不可以再分
MySQL_第1张图片

第二范式

存在非主属性对码的传递性依赖 R(A,B,C) A是码 A -->B ,B–>C
定义:如果关系模式R是第一范式的,而且关系中每一个非主属性不部分依赖于主键,称R是第二范式的(什么叫部分依赖:即某些非主属性只依赖与部分主键,如关系R(A,B,C,D)主键为(A,B),C只由B决定,则C部分依赖与主键)。
所以第二范式的主要任务就是
满足第一范式的前提下,消除部分函数依赖。
MySQL_第2张图片

第三范式

不存在非主属性对码的传递性依赖以及部分性依赖

BC范式(BCNF)

符合3NF,并且,主属性不依赖于主属性
若关系模式属于第一范式,且每个属性都不传递依赖于键码,则R属于BC范式。

通常
BC范式的条件有多种等价的表述:每个非平凡依赖的左边必须包含键码;每个决定因素必须包含键码。

BC范式既检查非主属性,又检查主属性。当只检查非主属性时,就成了第三范式。满足BC范式的关系都必然满足第三范式。
还可以这么说:若一个关系达到了第三范式,并且它只有一个候选码,或者它的每个候选码都是单属性,则该关系自然达到BC范式。

一般,一个数据库设计符合3NF或BCNF就可以了。在BC范式以上还有第四范式、第五范式。

范式总结

通俗地理解三个范式
  通俗地理解三个范式,对于数据库设计大有好处。在数据库设计中,为了更好地应用三个范式,就必须通俗地理解三个范式(通俗地理解是够用的理解,并不是最科学最准确的理解):
  第一范式:1NF是对属性的原子性约束,要求属性具有原子性,不可再分解;
  第二范式:2NF是对记录的惟一性约束,要求记录有惟一标识,即实体的惟一性;
  第三范式:3NF是对字段冗余性的约束,即任何字段不能由其他字段派生出来,它要求字段没有冗余。
  没有冗余的数据库设计可以做到。但是,没有冗余的数据库未必是最好的数据库,有时为了提高运行效率,就必须降低范式标准,适当保留冗余数据。具体做法是:在概念数据模型设计时遵守第三范式,降低范式标准的工作放到物理数据模型设计时考虑。降低范式就是增加字段,允许冗余。


2.数据库的一些基本操作

2.1 基本操作(创建,删除,增删改查)

数据库操作

创建数据库:Create DATABASE databasename
删除数据库:drop database databasename

表操作

创建新表:

create table tabname(col1 type1 [not null] [primary key],col2 type2 [not null],..)


根据已有的表创建新表:
select * into 目的数据库名.dbo.目的表名 from 原表名(使用旧表创建新表)
B:create table tab_new as select col1,col2… from tab_old definition only

删除表:drop table tabname

基本表操作(增删改查等)

  1. 增加一个列:
    Alter table tabname add colname coltype

  2. 删除一个列:
    Alter table tabname drop column colname

  3. 添加主键:
    Alter table tabname add primary key(col)
    说明:删除主键:Alter table tabname drop primary key(col)

  4. 修改字段类型:
    ALTER TABLE 表名 ALTER COLUMN 字段名 varchar(30) NOT NULL

  5. 更改数据库表字段类型:
    alter table page_shsjgrgl alter column s1 int

  6. select:


select [distinct ] * from 数据表 where 字段名=字段值 having ...  order by 字段名 [desc]

查询去除重复值:select * from table1

select **top 10** * from 数据表 where 字段名=字段值 order by 字段名 [desc]

  1. update:
sql="update 数据表 set 字段名=字段值 where 条件表达式"
  1. 删除数据记录:
    sql=“delete from 数据表 where 条件表达式”
    sql=“delete from 数据表” (将数据表所有记录删除)

  2. 添加数据
    sql=“insert into 数据表 (字段1,字段2,字段3 …) values (值1,值2,值3 …)”
    sql=“insert into 目标数据表 select * from 源数据表” (把源数据表的记录添加到目标数据表)

高级的操作

  1. 创建索引
    create [unique] index idxname on tabname(col…。)

  2. 删除索引
    drop index idxname on tabname
    注:索引是不可更改的,想更改必须删除重新建。

  3. 创建视图
    create view viewname as select statement

  4. 删除视图
    drop view viewname

  5. 数据记录统计函数:
    AVG(字段名) 得出一个表格栏平均值
    COUNT(*;字段名) 对数据行数的统计或对某一栏有值的数据行数统计
    MAX(字段名)
    MIN(字段名)
    SUM(字段名)

  6. 几个高级查询运算词
    A:UNION 运算符
    UNION 运算符通过组合其他两个结果表(例如TABLE1 和TABLE2)并消去表中任何重复行而派生出一个结果表。当 ALL 随UNION 一起使用时(即UNION ALL),不消除重复行。两种情况下,派生表的每一行不是来自TABLE1 就是来自TABLE2。

B: EXCEPT 运算符
EXCEPT 运算符通过包括所有在TABLE1 中但不在TABLE2 中的行并消除所有重复行而派生出一个结果表。当ALL 随EXCEPT 一起使用时(EXCEPT ALL),不消除重复行。

C:INTERSECT 运算符
INTERSECT 运算符通过只包括TABLE1 和TABLE2 中都有的行并消除所有重复行而派生出一个结果表。当ALL 随INTERSECT 一起使用时(INTERSECT ALL),不消除重复行。
注:使用运算词的几个查询结果行必须是一致的。

使用外连接
A、left outer join:
左外连接(左连接):结果集既包括连接表的匹配行,也包括左连接表的所有行。

SQL: select a.a, a.b, a.c, b.c, b.d, b.f from a LEFT OUT JOIN b ON a.a = b.c

B:right outer join:
右外连接(右连接):结果集既包括连接表的匹配连接行,也包括右连接表的所有行。

C:full outer join:
全外连接:不仅包括符号连接表的匹配行,还包括两个连接表中的所有记录。

例子

查询数据库中含有同一这字段的表:
select name from sysobjects where xtype = 'u' and id in(select id from syscolumns where name = 's3')


不同数据库之间的复制:

复制结构:
select * into test.dbo.b from GCRT.dbo.page_shsjgrgl where 1<>1

复制内容:
insert into test.dbo.b(xm,ssdq) select xm,ssdq from GCRT.dbo.page_shsjgrgl 

查看数据库中所有的数据表表名:
select name from SysObjects where type='u'


查询数据库时随机10条记录:
select top 10 * from td_areacode order by newid()

随机取出10条数据
select top 10 * from tablename order by newid()
随机选择记录
select newid()
删除重复记录
Delete from tablename where id not in (select max(id) from tablename group by col1,col2,...)

3.MySQL总体认识

3.1MySQL总体结构

Mysq架构图

MySQL_第3张图片

上面是客户端,连接管理

中间主要是连接,线程管理,在是 查询缓存和分析器,优化器

下面是存储引擎,在是系统存的文件系统

Mysql的物理文件组成

1.日志文件
错误日志文件,记录mysql server运行过程中遇到的严重错误信息以及启动关闭时的详细信息。
二进制日志文件:记录了Mysq中所有的修改数据库的操作,然后以二进制的形式存储在日志中,包括每条语句的执行时间和消耗的资源,和相关的事务信息。
查询日志:记录所有的查询语句。
慢查询日志:记录所有执行时间超过long_query_time变量的语句和达到min_examined_row_limit条距离的语句。
innoDB引擎在线redo日志:
2.数据文件
.frm文件:主要存放与表相关的数据,如表结构定义信息,当数据库崩溃时,可用它来恢复数据库表结构。
.myd文件:myisam存储引擎创建表时,都会有一个.myd文件用来存储数据表的数据文件。
.myi文件:主要用来存储数据文件中任何索引的数据树数。对于MyIsam类型的表,每一个表都会有一个.MYD文件和一个.MYI文件。
ibd文件和ibdata文件:用来存储InnoDB类型表的数据,包括索引数据。如果采用共享表空间,则采用ibdata文件(所有的表共享一个或多个ibdata文件)。如果是独享模式,则采用ibd文件。
其他文件:系统的配置文件。

Mysql存储引擎概述

Mysql存储引擎包括:MYISAM ,Innodb,BDB,memory,merge,ndb等
其中,Innodb为默认的存储引擎,支持外键和事务,支持行锁,存储限制为64TB
比较常用的存储引擎包括:myisam,innodb,memory,merge

Mysql工具

mysqladmin:
mysqldump:
mysql:
常用的参数:
-u: user
-p :password (直接写password时, 中间不用加空格,如-proot,表示密码为root
-P : port

3.2 权限管理与安全

3.2.1 权限表

权限表存放在mysql数据库中,由mysql_install_db脚本初始化,包括表:
user,db,host,tables_priv,columns_priv,procs_priv

user:
存储的是全局的性的权限,即表示对所有的数据库所有的权限。分为4种:用户基本信息类,权限类,安全类,资源控制类。基本的权限、资源型如下:
MySQL_第4张图片

主键为:host,user,password,登录时,需要这三项全部匹配

db:
存储的表示用户对某个数据库的权限,主键为:host,user,db.

host:
存储的那个主机对那个db有什么权限,不区分用户,主键为:host,db

tables_priv:
存储的用户对那个表具有什么权限,主键为:host,db,user,table_name

columns_priv:
存储的 存储的用户对那个表的那个列具有什么权限

procs_priv:
存储的对存储过程和存储函数的设置操作权限。

由于用户权限信息量比较小,访问比较频繁,mysql在启动后会将权限表信息缓存起来,所以手工的修改权限表后,都需要执行flush privileges指令来重新刷新缓冲区。
用户使用grant,revoke,drop user,create user 命令修改用户权限信息时,会自动刷新权限信息。
这里执行flush命令,需要reload权限

3.2.2.创建用户

**方式一:**直接使用create user语句。使用create user语句会直接在mysql.user中插入一条新记录,但是创建的用户没有任何权限。另外,使用create user语句需要有全局的create user权限或是mysql数据库的insert权限。

**方式二:**使用grant语句创建用户并授权
grant select,insert on . to ‘test3’@‘localhost’ identified by ‘test3’;

如果需要给用户test3授予能够在所有主机上的权限,则可用通配符%,如:
grant select,insert on . to ‘test3’@’%’ identified by ‘test3’;

如果需要让用户也可以授予,则在授予权限时,可加上 with grant option,这种命令需要由root帐号执行。
grant all on test.* to ‘test’@‘localhost’ with grant option;

注意:好像有时候在授权时,使用%给所有主机都授权,但是使用localhost主机登录时,还是不行,需要单独给localhost授权。
好像有时候在授权并创建用户时,创建了针对所用主机登录时的密码,但是使用localhost主机登录时,提示密码不对,还是不行,需要单独给localhost登录设置密码。
这两是在phpadmin5.6.2版本中进行测试的结果。

**方式三:**直接在mysql.user中插入表记录。

3.2.3.删除用户

删除普通用户:drop user ‘test1’@‘localhost’
直接操作mysql.user表

3.2.4 修改密码

root用户修改别人的密码
set password for ‘user’@‘localhost’ =password(‘userpassword’);

自己修改自己的密码:
set password=password(‘newpassword’);

3.2.5 权限管理

授权:
grant priv_Type on database.table,database.table To user [with grant option]
PS:使用with grant option可让被授权用户拥有授权权限

回收权限:
revoke all from ‘user’@‘host’ , ‘user’@‘host’
revoke priv_type on database.table ,database.table2 from ‘user’@‘host’
PS:在回收权限后,会在相应的表中删除相应的记录,但是user表中的记录还在,要删除user表中记录,需要使用drop user 语句

3.2.6 访问控制

访问控制分为两个阶段:连接核实阶段和请求核实阶段。
连接核实阶段:验证请求的host,user,password,与user表中的记录是否相符,如果不同,则拒绝连接。否则服务器接受连接,进入第二阶段。
请求核实:检查用户是否有足够的权限来执行请求。权限检查包括user表,db表,host表,tables_priv,columns_priv表。在确认时,首先检查user表,如果指定的权限没有在user表中授权,则到db表中找,依次类推,直到找到或是没有找到,请求没有足够的权限。
PS:对于用户登录时,需要结合IP,对于相同的用户,不同的IP,Mysql 也会认为是不同的用户。
PS2:mysql权限检查是逐级向下的,但是有的权限不需要检查那么多,如,用户登录后,执行的管理操作,则只检查user表。

3.2.7 Mysql中的安全问题

a:避免使用root用户运行MYSQL服务器:
主要是为了具有file权限的用户访问root用户创建的文件。
关于file权限:具有file权限的用户,能够执行从文件中装载数据的命令,如,load data infile ‘D:/txt.txt’ into table t5;

b:关闭不需要的服务:减轻服务器的负担。

c:修改root用户口令,删除匿名用户:mysql安装的时候,默认是无root用户密码的。
另外,mysql安装完后,mysql会初始化自动生成匿名帐号和test库(匿名账户对test数据库拥有大部分的权限)。如果存在匿名账户,则普通用户使用匿名帐号登录,执行大量的针对test库的耗时操作,则会导致服务器的性能下降。

d:设置安全密码:

e:不要把file,process,super权限授予管理员以外的帐号:
file权限:从文件中装载数据到数据库中
process权限:可以执行show processlist命令,查看当前用户正在执行的命令
super权限:能够指向kill命令,杀死用户线程(指向用户请求的线程)

关于:show processlist;(需要有process权限)
注意:只有有process权限,也能看到root用户正在执行的命令。关于正在二字的意义是:当你查询时,用户已经提交的,还没执行完的命令(一般的命令都是很快就能结束,一般显示不了,除非命令被阻塞了)。
如:test6用户锁住了user表,然后root用户登录,修改密码,执行set password=password(‘root’)命令,因为A锁住了user表,所以root用户修改密码的密码会被阻塞。这时,test用户登录执行show processlist就能看到root用户提交的命令:
MySQL_第5张图片

当test6释放锁了之后,root用户的的命令能里面完成,test在使用show processlist则就看不到什么东西了
MySQL_第6张图片

关于super权限:kill id ;需要有super权限
如test,test6用户同时登录到mysql.
test执行kill命令,杀死test6用户线程
MySQL_第7张图片

之后,test6用户执行sql操作:
这里写图片描述

就能看到已经连不上了,需要退出重新登录。

f:限制用户的连接次数:使用max_user_connection参数限制用户的最大连接数
其他的资源权限还有:
MySQL_第8张图片

g:记住Revoke all的缺陷:
revoke all privileges on . from ‘test’@‘localhost’;
mysql在这里是存在漏洞:如果使用了多条语句给用户授权了,在revoke all的时候,只会撤销一条授权语句,如:

使用了三次授权语句为用户授权:
MySQL_第9张图片

revoke all之后:还是会存在其他的权限:
MySQL_第10张图片
这时test还是具有mysql,test数据的权限,因此,在使用revoke all时一定要确保此时该用户没有其他授权条目了!

3.3 数据备份与还原

3.3.1 数据库备份

方式一:mysqldump工具的使用
mysqldump -u user -h host -p dbname [tabname,tbname…] > filename.sql
导出的内容包括数据库的结构,表结构,数据,一些注释语句(以/*!开头的注释是mysql的命令,对其他数据库管理系统会被忽略,这些语句开头的数据表明只有指定的mysql版本或是高版本才会执行)
形式就和XMAPP登录后,导出功能相似,里面都是sql语句

MySQL_第11张图片

MySQL_第12张图片
使用mysqldump可备份单个表,多个表,数据库,多个数据库(使用–databases 参数),如:
mysql -u user -h host -p --databases database1 database2

相对其他方式来说比较慢,但是这种方式可用户所有类型的表,且具有移植性

方式二:直接复制整个数据库目录
简单,但是对于innodb存储引擎表不适用。且不同的版本之间可能不兼容。
方式三:使用mysqlhotcopy快速备份
比较快,但是只适用与myisam,archive类型的表

3.3.2 mysqldump中的一些参数

–add-drop-database:在每个create databse 语句前加上drop database语句
–add-drop-tables:在每个create table 语句前加上drop table语句
–no-create-info:只导出数据,而不添加create table语句
–no-data :不写表数据,只转储表结构

3.3.3.数据还原

方式一:使用mysql命令还原
a: mysql -u user -p [dbname] 如:mysql -u root -p booksdb < c:/backup/booksdb.sql
需要已经存在booksdb数据库。

b:如果应经登录,则可用source命令导入source文件,格式如下:
source filename;
如: source c:/backup/booksdb.sql
PS :在使用source命令的时候,需要先选择数据库(use dbname)

方式二:直接复制数据库文件到数据库目录
针对myisam表适用,不适用与innodb

方式三:使用mysqlhotcopy快速恢复

3.3. 4.数据库迁移

一:相同版本间的数据库迁移
对于myisam,赋值目录就可。如果包涵其他存储引擎的表,最好还是通过mysqldump命令

案例:从www.abc.com主机上的数据迁移到www.bcd.com上
如:mysqldum -h www.abc.com -u root -ppassword dbname | mysql -h www.bcd.com -uroot -ppassword

二:不同版本之前的mysql数据库之间的迁移
最好还是用mysqldump工具,但是需要注意:不同版本的数据库默认的字符集可能不同,对于中文数据,可能会出现乱码,这里需要配置。

三:不同数据库之间的迁移
不同的数据库实现的sql标准不同,这时应该采用一些中间工具来将sql数据格式标准化

3.3. 5.表的的导入导出

将表中的某些数据导出到存储文件中。mysql数据库数据可导出为sql文件,xml文件,html文件,txt文件。
一:使用select … into outfile导出(需要有file权限)
格式:select colunmlist from table where condition into outfile ‘filename’ [options]

    --options选项:
            fields terminated by 'value'  :设置字段间的分隔符
            fields [optionally]enclosed by 'value' :设置字段的包尾字符,如果使用了optionally,则只有char,varchar等字符数据被包围。
            fields escaped by 'value' :设置转义字符,默认值为‘\’
            lines starting by 'value'
            lines terminated by 'value'

特点:能快速的转储表数据,但是只能存到服务器上。如果需要将数据存在服务器之外的主机上,则应该使用mysql -e “select …” >filename这样的命令,来生成文件。

二:使用mysqldump 命令导出文本文件
导出文本文件的格式为;
mysqldump -T path -u user -p dbname [tables] [options]

–options选项:
–fields-terminated-by=value :设置字段间的分隔符
–fields–enclosed-by=value :设置字段的包尾字符,如果使用了optionally,则只有char,varchar等字符数据被包围。
–fields-escaped-by=value :设置转义字符,默认值为‘\’
–lines-starting-by=value
–lines-terminated-by=value

PS :这里的value不需要用引号括起来。

例:将test数据库中的person表中的记录导出到文本文件中,要求字段间使用‘,’间隔,字符类型的字段值使用双引号括起来,每行记录以’\r\n’结尾。
mysqldump -T C:/backup test person -u root -p --fields-terminated-by=,
–fields-optionally-enclosed-by=" --fields-terminated-by=\r\n

结果产生两个文件:一个是sql文件,用来存储结构,一个txt文件,用来存储数据
PS:关于系统的文件目录,写成linux下的/或是windows下的\都可以。

三:用mysql命令导出文本文件
使用mysql在命令行模式下执行sql指令,将查询结果保存到文本文件中。
mysql -u root -p --execute="select … " dbname >filename.txt
使用–execute选项,表示执行该选项后面的语句并退出,后面的语句用双引号括起来。
例: mysql -u root -p --execute=“select * from score;” test --html >c:\backup\person.html
PS :该种方式只导出数据,不导出表结构,只有一个文件。另外,好像直接导出到盘根目录下是没有写权限的,需要导入到目录中。
MySQL_第13张图片
MySQL_第14张图片

PS:还可导出xml文件,加上 --xml,如果什么都不加,就是txt的格式。

四:load data infile导入文本文件
格式:load data infile ‘filename.txt’ into table tablename [option ] [ignore number lines]

--options选项:
            fields terminated by 'value'  :设置字段间的分隔符
            fields [optionally]enclosed by 'value' :设置字段的包尾字符,如果使用了optionally,则只有char,varchar等字符数据被包围。
            fields escaped by 'value' :设置转义字符,默认值为‘\’
            lines starting by 'value'
            lines terminated by 'value'

3.4 高级特性

mysql的高级特性,包括查询缓存、合并表,分区表,事务

3.4.1.查询缓存

缓存机制就是mysql会将一些可缓存的查询语句和它的结果缓存起来,下次查询的时候会直接从缓存中取结果。
查询缓存会缓存最近的结果。如果在查询缓存之后,有新的事务改变了查询缓存中的结果,则缓存会自动失效。
对于频繁更新的表,设置查询缓存是不合适的,这会导致缓存的频繁失效。
开启查询缓存
mysqld --query_cache_type=1 ;使mysql服务器已支持查询缓存的方式启动
查询当前查询缓存状态:
select @@query_cache_type;
关闭查询缓存:
set session query_cache_type=off;

查询系统变量query_cache_size的大小(数据库分配给查询缓存的内存大小)
select @@global.query_cache_size;

设置该参数:
set @@global.query_cache_size=1024000;

查询查询缓存的最大值
select @@global.query_cache_limit;

关于查询缓存的最大值:
如果查询结果很大,查询缓存缓存不了(就不会缓存),则需要调大query_cache_limit,该值用来设置每条查询缓存的的最大值,默认值为1M。
关于查询缓存的效率:
一:先使用show variables like '%query_cache%'查询缓存相关数据:
MySQL_第15张图片

参数:
        have_query_cache:是否支持查询缓存
        query_cache_min_res_unit:用来分配内存块的最小体积。每次给查询结果分配内存时,默认分配4096字节(分配的最小单位)
        query_cache_size:查询缓存使用的总内存字节数
        query_cache_limit: MySQL能够缓存的最大结果,如果超出,则增加 Qcache_not_cached的值,并删除查询结果
        query_cache_wlock_invalidate: 如果某个数据表被锁住,是否仍然从缓存中返回数据,默认是OFF,表示仍然可以返回

二:查询查询缓存的效率
show status like ‘Qcache_hits’;
MySQL_第16张图片

在查询了4次后显示命中率为3

三:监控查询缓冲的性能
维护查询缓存的命令:
(1)flush query cache:整理查询缓存,不会从缓存中移除任何的查询结果,而是用户整理查询缓存的内存空间碎片问题。
(2)reset query cache:移除所有的查询缓存。
(3)show status like ‘%Qcache%’ :监控查询缓存的使用情况
MySQL_第17张图片

GLOBAL STAUS 中 关于 缓存的参数解释:
        Qcache_free_blocks: 缓存池中空闲块的个数
        Qcache_free_memory: 缓存中空闲内存量
        Qcache_hits: 缓存命中次数
        Qcache_inserts: 缓存写入次数
        Qcache_lowmen_prunes: 因内存不足删除缓存次数
        Qcache_not_cached: 查询未被缓存次数,例如查询结果超出缓存块大小,查询中包含可变函数等
        Qcache_queries_in_cache: 当前缓存中缓存的SQL数量
        Qcache_total_blocks: 缓存总block数

命中条件
缓存存在一个hash表中,通过查询SQL,查询数据库,客户端协议等作为key.在判断是否命中前,MySQL不会解析SQL,而是直接使用SQL去查询缓存,SQL任何字符上的不同,如空格,注释,都会导致缓存不命中.

如果查询中有不确定数据,例如CURRENT_DATE()和NOW()函数,那么查询完毕后则不会被缓存.所以,包含不确定数据的查询是肯定不会找到可用缓存的

工作流程
a. 服务器接收SQL,以SQL和一些其他条件为key查找缓存表(额外性能消耗)
b. 如果找到了缓存,则直接返回缓存(性能提升)
c. 如果没有找到缓存,则执行SQL查询,包括原来的SQL解析,优化等.
d. 执行完SQL查询结果以后,将SQL查询结果存入缓存表(额外性能消耗)

缓存失效

当某个表正在写入数据,则这个表的缓存(命中检查,缓存写入等)将会处于失效状态.
在Innodb中,如果某个事务修改了表,则这个表的缓存在事务提交前都会处于失效状态,在这个事务提交前,这个表的相关查询都无法被缓存.

缓存的内存管理

缓存会在内存中开辟一块内存(query_cache_size)来维护缓存数据,其中有大概40K的空间是用来维护缓存的元数据的,例如空间内存,数据表和查询结果的映射,SQL和查询结果的映射等.

MySQL将这个大内存块分为小的内存块(query_cache_min_res_unit),每个小块中存储自身的类型,大小和查询结果数据,还有指向前后内存块的指针.

MySQL需要设置单个小存储块的大小,在SQL查询开始(还未得到结果)时就去申请一块空间,所以即使你的缓存数据没有达到这个大小,也需要用这个大小的数据块去存(这点跟Linux文件系统的Block一样).如果结果超出这个内存块的大小,则需要再去申请一个内存块.当查询完成发现申请的内存块有富余,则会将富余的空间释放掉,这就会造成内存碎片问题,见下图

MySQL_第18张图片

减少碎片策略

  1. 选择合适的block大小
  2. 使用 FLUSH QUERY CACHE 命令整理碎片.这个命令在整理缓存期间,会导致其他连接无法使用查询缓存
    PS: 清空缓存的命令式 RESET QUERY CACHE

查询缓存问题分析
MySQL_第19张图片

提高查询缓存的效率:

a.sql中的语句不分大小写,但是,在查询缓存中匹配sql语句中,大小写不同的sql语句会被当成不同的查询。
b.当客户端和服务器使用不同的字符集的时候,查询数据可能会因为字符集不同的原因而没有被数据库缓存起来。
c.对于频繁更新的表,使用查询缓存是不合理的。这是应该尽量使用分区表,把总是要更新的数据放入一块,另一块存放稳定的数据,来提高查询缓存的命中率。
d.同c,在数据库设计时,尽量不用使用一张大表,因为表一更新,该表相关的缓存就会失效,而应该分成许多的小表。
e.对数据库写的时候,尽量一次写入。因为逐个写入的话,每次写入都会让数据库缓存失效或清理,此时,可能造成服务器挂起长时间。
f.如果想少数查询使用查询缓存,多数不实用查询缓存,则可以将query_cache_type设置为demand,然后在想使用缓存的语句后面加上sql_cache,不想使用的语句后面加上 sql_no_cache开控制缓存。

3.4. 2.合并表和分区表

合并表:存储引擎为merge,是一组myisam表的组合,其实存储的数据还是存储在子表里,在操作merge表的时候,操作会转化成对各个子表的操作。相当于提供了一个盒子,将各个子表放进去了(主要是提高了并发,但是和分区表不同的是,合并表中的子表是存在的,而分区表是对用户透明的)

分区表:将一张大表根据某些条件分成若干分区。这是属于物理数据的设计技术,主要目的是让某些特定的查询操作减少响应时间,对于应用来说,分区是完全透明的。可分为水平分区和垂直分区。
对于水平分区,是通过表的某个属性作为分割条件。
查询是否支持分区: show variables like ‘%partition%’

水平分区分为:range分区,list分区,hash分区,key分区等。

range分区:

创建range分区:使用 values less than (),也可使用表达式,但是结果不能为null

create table emp(no varchar(20) not null,name varchar(20),salary int ) 
partition by range(salary)
        (
            partition p1 values less than (1000),
            partition p2 values less than (2000),
            partition p3 values less than maxvalue
            );



create table emp(no varchar(20) not null,name varchar(20),salary int,birthday date ) 
partition by range( year(birthday) )
        (
            partition p1 values less than (1990),
            partition p2 values less than (2000),
            partition p3 values less than maxvalue
            );

删除分区:ALTER TABLE emp DROP PARTITION p2
PS:maxvalue表示最大的可能的整形值

list分区

创建list分区:和range相同,只是list的分区是基于值是否处于某个集合来划分
create table emp(no varchar(20) not null,name varchar(20),salary int,depno int )
partition by list(depno)
(
partition p1 values in (10,20),
partition p2 values in (30,40),
partition p3 values in (40)
);

按照部分号分区

创建hash分区:

create table emp(no varchar(20) not null,name varchar(20),salary int,depno int,birthday date not null )
partition by hash( year(birthday) )
partitions 4;
线性hash分区:没看懂
key分区:没看懂
复合分区:即分区还可以在分区。

3.4. 3.事务控制

mysql事务管理通过:set autocommit, start transaction, commit, rollback等语句控制本地事务。
默认情况下,mysql是自动提交的,即每个sql都是一个事务。这种情况下,效率不是很高,如一次执行1000条插入,则会有1000个事务,提交了1000次。关闭自动提交功能:set @@autocommit=0;
查看是否关闭自动提交: show variables like “autocommit”;

3.4.4.分布式事务

分布式式事务涉及一个或多个资源管理器,一个事务管理器。不同的节点相互协同工作,保证共同完成一个具有逻辑完整的植物。
资源管理器:向事务管理器提交事务,回滚。同时给事务提供资源。数据库就是一种资源管理器。
事务管理器:和每个资源管理器通信,协调事务的处理。
一个分布式的事务中的各个事务都是分布式事务的‘分支事务’。分布式事务和各分支通过一种命名方式标识。

用于执行分布式事务的过程分为两个阶段:
a:所有分支被预备。它们被事务管理器告知要准备提交事务,每个分支资源管理器记录分支的行动,并指示任务的可行性。
b:事务管理器告知资源管理器是否要提交或者回滚。如果预备分支时,所有的分支都指向它们的能够提交,则所有的分支都给告知提交。如果一个分支出错,那么都要回滚。特殊情况下,只有一个分支的时候,第二阶段被省略。

3.5 锁

mysql对于不同的存储引擎,支持不同的锁机制,这是mysql的数据库的一个显著的特定

3.5. 1.锁机制概述

mysql的三种级别的锁机制为:行级锁,页级锁,表机锁

行级锁:
最大特点是锁定对象的粒度小,但是获取锁和释放锁的消耗比较大,加锁比较慢,容易发生死锁。行级锁不是mysql自己实现的锁定方式,而是由其他存储引擎锁实现的,如InnoDB.在InnoDB中,为了让行锁和表锁共存,内部还使用了意向锁。

页级锁:粒度介于行级锁 和表锁之间。

表机锁:粒度最大,系统开销小。一次性将整个表锁定,因此很好的避免死锁问题。但是由于粒度大,发生锁冲突的概率也高。
表锁分为两种类型:读锁定,和写锁定。使用4中对列来维护这4中锁,有:
current read lock queue
padding read lock queue
current write lock queue
padding write lock queue
其中,current read lock queue中存放的是当前持有读锁的线程,padding read lock queue存放的是等待资源的信息。

3.5. 2.MyIsam表锁

查询Myisam表锁的争用情况: show status like ‘table_lock%’
MySQL_第20张图片

table_locks_immediate :产生表锁定的次数
table_locks_waited:出现表锁争用而等待次数

MYISAM在读操作占主导的情况下是高效的,可一旦出现大量读写并发,同innodb相比,效率就明显降低。对于myisam存储引擎表,新的数据会附加到文件的结尾,可如果经常做一些update和delete操作,数据将是不连续的。之后在插入数据时,默认情况下先看这些空洞是否可以容纳新的数据,此时在插入新的数据,如果可以,则插入到空洞里去。否则,插入到文件尾。这样做是为了减少文件的大小,降低产生文件碎片。

3.5. 对于MyISAM表锁的一些优化:

a.当对同一个myisam表进行插入和查询操作时,为了降低锁竞争频率,可以将concurrent_insert的值置为2(set @@global.concurrent_insert=2 或是set global concurrent_insert=2),此时不管表有没有空洞,都运行数据文件结尾并发的插入数据,对于文件碎片问题,可以定期使用optimize table语法进行优化。
b.在默认的情况下,写操作的优先级要高于读操作的优先级。即使是先发出读操作,后发送写请求,处理时,也会优先处理写请求。可以将设置 max_write_lock_count=1 (set global max_write_lock_count=1;),此时当系统处理完一个写操作之后,就会暂停写操作,给读操作执行的机会
c.降低写操作的优先级,给读操作更高的优先级级别,可以将low-priority-updates设置为1.
d.减少锁定时间,尽量让查询的时间尽可能短。比较复杂的查询语句可以分解成多个较少的查询。尽可能建立高效的索引,让数据检索的快一点。

Myisam表级锁加锁方法
MyIsam在执行查询语句的时候,会自动给查询语句涉及的数据库表加读锁,在执行更新操作时,会自动给设计的表加写锁。
对于myisam表锁手动加锁方式为:lock table tb1_name [as alias] {red [local] | [low_priority] write} 。需要有lock table,select权限。
使用unlock tables 来释放锁。

PS :关于read 和read local之前的区别:允许在锁定被保持时,执行非冲突性的insert语句同时插入,其作用是在满足myisam表并发插入条件的情况下,运行其他用户在表尾并发插入记录。

Myisam表级锁的concurrent_insert特性
a.当concurrent_insert=0时,不允许并发插入
b.当concurrent_insert=1时,如果表中没有被删除的行,myIsam允许一个进程在读表的同时,另一个进程从表尾插入。
c.当concurrent_insert=2时,无论表中有没有被删除的行,myIsam都运行在表尾并发插入。

3.5. 3.InnoDB行锁

事务的特性ACID

  • a.原子性 b.一致性 c.隔离性 d.持久性

事务的隔离级别:

  • a.读未提交 b.读提交 c.可重复读 d.串行化

关于幻读:事务在操作过程中,进行两次查询,第二次查询的结果包含了第一次没有出现的数据。出现幻读的原因主要是两次查询过程中,另一个事务插入了新的数据。(mysql通过间隙锁来防止幻读)

关于不可重复读:一个事务对一行数据重复读写了两次,可是得到了不同的结果。在两次读取数据的中途,有可能存在另一个事务对数据进行了修改。

查看当前默认的事务隔离级别:select @@tx_isolation
MySQL_第21张图片

Mysql中的REPEATBLE READ 级别并不能完全避免幻读,需要显示加next key locks,可以显示加间隙锁(select * where * for update or lock in share mode)

如果使用普通的读,会得到一致性的结果,如果使用了加锁的读,就会读到“最新的”“提交”读的结果。(我的理解是,如果主动加上锁,在加锁的时候,mysql会去匹配当前表中的记录,然后加上行锁,所以能得到最新的结果。)

本身,可重复读和提交读是矛盾的。在同一个事务里,如果保证了可重复读,就会看不到其他事务的提交,违背了提交读;如果保证了提交读,就会导致前后两次读到的结果不一致,违背了可重复读。

可以这么讲,InnoDB提供了这样的机制,在默认的可重复读的隔离级别里,可以使用加锁读去查询最新的数据。

获取InnoDB 行锁的争用情况
show status like ‘%innodb_row_lock%’
MySQL_第22张图片

InnoDB行锁的实现方法
innodb行锁是通过给索引上的索引项加锁来实现的,innodb行锁只有通过索引条件检索数据时,才使用行锁,否则innoDb会使用表锁。(只要有索引,不管索引是主键索引还是唯一索引,或是普通索引,InnoDB都会使用行锁来对数据加锁。

PS:当不同的事务可以使用不同的索引锁定相同的行,也会发生等待锁。
如果表上有索引,但是不是通过索引来锁定查找记录的,就会使用表锁

3.5.4.关于间隙锁

所谓的间隙锁是指:Innodb存储引擎在更新某个区间数据时,将会锁定这个区间的所有记录,例如:update xx where id between 1 and 100,测试它会锁住id从1 到100之间的所有记录。另外,在这个区间中不存在的记录,也会被锁住,比如这时候不存在id=89的记录。这时候,另外一个事务插入一个记录,id=89,也需要等待上一个事务释放锁资源。
InnoDB使用间隙锁的主要目的是为了防止幻读。间隙锁在repeat read级别是要显示加锁的。

3.5. 5.innoDB行锁优化

InnoDB存储引擎实现了行级锁,在加锁粒度上更小,但是,显示更为复杂,带来的性能损耗也更高。但是在InnoDB上的并发性能也远远高于表级锁。当系统并发度比较高时,Innodb的整体性能要远远优于Myisam.
为了提高InnoDB的性能,尽量做到如下几点:
a.控制事务的大小,减少锁定资源量和锁定时间长度。

b.让所有数据检索通过索引来完成,避免在InnoDB中使用表锁。

c.减少基于范围的数据检索,避免因为间隙锁带来的负面影响。

d.在业务允许的情况下,尽量使用级别较低的事务级别,减少因为事务隔离级别带来的附加成本。

e.合理使用索引。

f.在应用中,尽可能的按照相同的访问顺序来访问,防止产生死锁。

g.对于容易产生死锁的业务,可以放弃使用innodb行锁,尝试使用表级锁来减少死锁的概率。

3.6 性能优化

3.6.1 优化简介

优化原则:减少系统瓶颈,减少资源的占用,增加系统的反应速度。如优化文件系统,通过磁盘I/O读写速度,通过优化操作系统调度策略,优化表结构,索引,查询语句使查询响应更快。
查询mysql的数据库性能参数:show status like ‘value’
一些常用的性能参数:

        Connections:连接mysql的次数
        Uptime:mysql服务器上线时间
        slow_queries:慢查询次数
        com_select:查询操作次数
        com_update:插入操作次数
        com_delete:删除操作次数

3.6.2.Mysql query optimizer概述

mysql中有一个专门负责优化select语句的优化器模块,该优化器结合数据库系统收集的各种统计信息,为客户端的sql进行查询优化,如常量转化,无效内容删除,常量计算等。query optimizer会分析出最优的数据检索方式,即执行计划。

3.6. 3.利用Explain分析查询语句

语句:explain [extended] select select_options
如:explain select * from mysql.user;
MySQL_第23张图片

explain结果字段意义:
1.id:select标识符,表示该select部分的查询序列号,值越大优先级越高。
2.select_type:表示select类型,包括simple, primary,union,union result,depentden union,subquery,derived,dependent subquery等。
3.table:表示该查询是关于那张表的
4.type:表的连接类型,包括system,const,eq_ref,ref,ref_or_null,index_merge,unique_subquery,index_subquery,range,index,all.
5.key:表示实际查询使用到的索引,如果没有选择索引,则该列的值为null.
6.key_len:
7.possible_keys:
8.ref:表示使用那个列或常数来一起查询
9.row:显示在表查询时必须检查的行数。
10.extra:其他在处理sql时的详细信息,包括:

        a.using index:使用了索引
        b.using where:说明服务器对行过滤了
        c.using temporary:使用了临时表进行排序
        d.using filesort:使用一个外部索引排序。

3.6. 4.合理使用索引优化查询

在使用了索引列来过滤行时,可大大的提高sql执行效率。但是有几种特殊情况,使用了索引并没有太大的效果:

a.使用like关键字的查询,如果匹配的第一个字符为%,则索引不会起作用

b.在使用多列索引时,只有查询条件中包含了第一字段中,索引才会起作用。

c.使用or关键字的查询中,只有前后两个条件都是索引时,查询中才会使用。

3.6. 5.不同类型的sql语句优化

a.inset语句
mysql执行inset语句的大致步骤如下:

  客户端连接mysql服务器
  客户端发送insert语句
  服务器解析insert语句
  服务器增加数据
  服务器给增加的记录添加索引
  服务器关闭连接

由上看出,一次性插入多条记录比单个的插入多条数据要块,如:insert into books values(1,‘b1’),(2,‘b2’);
对于myisam表,可使用insert delay into 语句提交。该方式提交给mysql服务器时,服务器返回ok状态给客户端,但不立即将数据插入到表,而是存储到内存队列中,直到mysql服务器有空闲时插入。好处是提高插入速度,缺点是如果系统崩溃,则mysql还没有写入到磁盘中的数据将会丢失。

另外,可以通过将表锁定来加速insert语句。如果不加锁,每一次执行insert语句后,索引缓存区都会被写到磁盘上,而加锁后,索引缓存区仅被写入磁盘一次(也就是关闭自动提交,在innodb中)

b.优化order by子句
在order by子句中使用索引做排序字段,则不需要额外的排序。
另外,不要对where 和order的选项使用表达式或是函数,这样会使索引不起作用,如select * from table order by year(date) limit 0,30;

c.优化group by子句
在使用group by子句时,mysql会对符合的结果自动排序。通过扫描整个表并创建临时表,表中的每个组的行都是连续的,然后使用该临时表来找到组,并应用累计行数。在某些情况下,mysql可以通过索引而不用临时表,通过制定order by null禁止排序,从而节省损耗。

d.优化嵌套查询
子查询虽然很灵活,但是执行效率不高。在执行子查询时,mysql底层需要为内层查询的查询结果建立一个临时表,然后外层查询语句从临时表中查询记录。查询完后再撤销这些临时表。在mysql中,可以使用连接(join)来代替子查询。在mysql中,连接查询不需要使用临时表,速度比子查询快。

e.优化or条件,在条件上使用索引,则每个条件都要使用索引

3.6.6.优化数据库结构

a.将字段很多的表分解成多个表,将不常用字段分离出去。
b.增加中间表,把需要经常联合查询的数据插入到中间表,江河将之前的联合查询改为对中间表的查询。
c.增加冗余字段,减少多表连接。

3.6. 7.分析表,检查表,优化表

optimize table:优化表,如减少表文件空洞。
analysze table:
check table:

3.6. 8 服务器配置优化

a.关于key_buffer_size:
针对MyISAM表,用来设置索引块缓存的大小。可以设置多个key_buffer,并定制将表的索引缓存到制定的key_buffer,这样就可以降低线程之间的竞争。
如果需要删除自定义的key_buffer,则可将key_buffer大小设置为0即可。

b.关于table_cache设置
针对MyIsam表,表示用户打开表的缓存数量。当一个连接访问一个表时,如果该表已经在缓存中打开,则会直接访问缓存中的信息,如果没有缓存,而且当前缓存没有达到table_cache数量,则会将表缓存起来,如果达到了table_cache值,则会根据缓存的最后查询时间,查询率等规则释放之前的缓存,然后再将表缓存起来。
相关参数:
open_tables:当前打开表的缓存数
opened_tables:曾经打开的表缓存的数。如果执行flush table,则系统关闭当前没有使用的表缓存,因此,flush
table之后,open_tables会减少,而opened_tables不会变。

c.innodb_buffer_pool_size的设置
设置缓存innodb表和索引数据(相当与table_cache+key_buffer_size,针对myisam)。该参数不能动态设置,要修改这个值,必须重启mysqld服务。

d.关于innodb_addtional_mem_pool设置
用来设置InnoDB存储数据目录信息和其他内部数据结构的内存池大小。对于稳定的应用,这个参数相对稳定。
e.关于日志和事物参数的设置
inodb_log_file_size:设置日志组中每个日志文件的大小。如果日志文件较小,则日志切换频繁。如果日志文件较大,则系统灾难恢复时间较大。
innodb_log_files_in_group:默认两个,可能因为出现跨日志的大事务,所以一般来说,建议使用3-4个日志组。
innodb_log_buffer_size:日志缓存的大小。一旦提交事务,该缓存池中的内容会写到磁盘中。
innodb_flush_log_at_trx_commit:用来控制缓冲区中的数据写入到日志文件和将日志文件数据刷新到磁盘的操作时间。

f.关于存储和io相关的参数设置
innodb_open_files:限制innodb存储引擎在同一时间能打开的表的数量。
innodb_flush_method:
innodb_max_dirty_pages_pct:控制innodb的脏页在缓冲中的百分比,将脏页的比例控制在所设定的比例之下。如果参数为50,则脏页在缓冲中最多占50%。如果设置太大,则每次更新需要置换的数据页太大。如果太小,存放的脏页的缓存区太小。

g.其他参数
max_connect_errors:物理机最多连接异常数,如果超过该值,则再也无法连接上了。此时要么重启服务器,要么flush hosts。
interactive_timeout:交互连接模式中,服务器强制关闭连接的等待时间。
wait_timeout:非交互连接模式下,服务器强制关闭连接的等待时间。(正对tcp/ip连接和socket连接)
query_cache_type:
query_cache_size:

h.关于i/o优化
优化磁盘访问,如使用raid;设置符号连接,将数据库指向不同的物理磁盘。

3.6. 9 并发设置

    max_connections:
    max_allowed_packet:

3.6. 10 线程优化

mysql中实现了线程池。
关于线程相关的参数有:show variables like ‘thread%’ ;
MySQL_第24张图片

3.6. 11关于临时表的优化

临时表分为内存临时表和磁盘临时表。内存临时表由memory存储引擎处理。tmp_table_size参数指定了内存临时表的最大值,如果临时表超过了该值,则数据库会将数据存储在磁盘临时文件中。
show global status like ‘created_tmp%’ ;
查看临时表的状态
MySQL_第25张图片

3.6. 12 关于mysql replication

指主从服务器之间的自动的复制,同步,可从一台主服务器将数据复制到另一台或多台从服务器中(slave)的过程,这个过程是异步的,新版本的也支撑半同步。
数据库复制的大致三个步骤:

  1. 主服务器将数据的改变记录到二进制日志中
  2. 从服务器将主服务器的二进制日志事件(binary log events)复制到它的中继日志中
  3. 从服务器重做中继日志中的事件,将数据改变与主服务器保存同步。

主服务器收到事物请求后,先写二进制日志,然后将事物更新。

  1. 从服务器上的i/o进程连接主服务器,发出日志请求,master接受来自从服务器的i/o请求,负责复制的i/o进程根据请求信息读取制定日志制定位置之后的日志信息,返回给slave的io进程。
  2. 返回信息处理日志所包含的信息之外,还包括本次返回信息已经到master端的bin-log的名次和偏移。
  3. 从服务器接收到信息后,将接受到的日志内容添加到relay-log文件的末端,并将master的bin-log的文件名和偏移记录到master-info中。

在进行主从复制时,首先需要配置主从服务器。

  1. 在master端开启binlog日志。在my.ini文件中配置log-bin,默认是不开启二进制日志功能的。
    MySQL_第26张图片
  2. 主master中配置具有复制权限的账户,从服务使用该账户连接主服务器。
  3. 将主服务器中的初始数据库信息导入到从服务器中(可使用mysqldump,这是其实就是要在从服务器中建立和主服务器相同的数据库)
  4. 配置从服务器。有两种方法:
    a.使用change master to 命令,格式为 change master to master_host=,master_port=,master_user=,master_password=;
    b.直接在配置文件my.ini中配置这些参数

3.6. 13 服务器启动参数(和复制相关的)

**log-slave-updates:**用来配置从服务器的更新是否需要写入二进制日志,该选项默认是不打开的。如果这个从服务器同时也作为其他服务器的主服务器,搭建一个链式的复制,那个就需要开启这个选项,这样其他的从服务器才能获得它的二进制日志进行同步。
**master-connect-retry:**在和主服务器连接丢失的时候,重试的时间间隔,默认是60s.
**read-only:**用来限制普通用户对数据库的更新,确保从服务器的安全,但是root用户还是可以进行更新操作。使用语法如下:mysqld_safe -read-only&
**slave-skip-errors:**在从服务器执行binlog中错误的sql语句中,如果此时不忽略错误,从服务器会停止复制进程,等待用户处理错误。这种错误如果不能及时发现,将会对应用或者是备份产生影响。slave-skip-errors可以设置可以跳过的错误号,如果设置成all,则表示跳过所有的错误,
具体语法为:vi my.cnf
slave-skip-errors=1007,1051,1062

设置该参数需要注意:设置不当,可能导致主从服务器数据不一致。如果从服务器只是为了给主服务器分担查询压力,对数据的完整性要求不是很严格,则可以使用这个选项减轻数据库管理员的压力。

PS :在配置复制时,可配置复制的具体表,数据库
在my.cnf中配置:
replicate-do-table=tablename
replicate-ignore-table=tablename
replicate-do-dbtablename
replicate-ignore-db=tablename

复制管理
a.查看复制状态,show slave status;
b.复制服务器出错的原因:
问题一:‘log event entry exceede max_allowed_pack’错误
在应用中出现使用大的blob列或是长字符串,那么在从服务器上复制时,可能会出现上面错误。可在主服务器上添加max_allowed_packet参数,如 set @@global.max_allowed_packet=1677216,也可通过配置文件设置。
问题二:多主复制时的自增长变量冲突问题
从多个主服务器中复制数据,可能出现子增长变量冲突,可通过 auto_increment_increment,auto_increment_offset配置。

MySQL_第27张图片

实验:auto_increment_offset,auto_increment_increment配置
a.创建表: create table au(data int primary key auto_increment)engine=myisam;
b.插入记录:insert into au values(null),(null),(null);
c.查看增长号:
MySQL_第28张图片
d.改变auto_increment_increment

MySQL_第29张图片

e.插入记录:insert into au values(null),(null),(null);
f.查看增长号:

g.改变auto_increment_offset
set @@auto_increment_offset=5;
h.插入数据,查询:

MySQL_第30张图片

当修改auto_increment_offset之后的第一个auto_increment值一定是能够满足大于当前auto_increment最大值的最小倍数值,
之后再插入新值增量就为auto_increment_increment了。
MySQL_第31张图片
可以看到,再次增加新值之后,就按auto_increment_increment(=10)进行新增

3.6. 14 切换主从服务器

步骤:
a.确保从服务器已经执行完了relay log中的全部更新,看show prceslist中connect命令是否为‘has read all rely log’
b.关闭slave服务。执行reset master,重置成主服务(确保将该从服务器中的bin-log打开)
c.配置该从服务器上的复制权限的账户。
d.修改其他从服务器的配置,修改它们的master host等信息。

3.6. 15 mysql cluster

MySQL Cluster 是 MySQL 适合于分布式计算环境的高实用、高冗余版本。它采用了NDB Cluster 存储引擎,允许在1个 Cluster 中运行多个MySQL服务器。

目前,MySQL Cluster的 Cluster部分可独立于MySQL服务器进行配置。在MySQL Cluster中, Cluster的每个部分被视为1个节点。
管理(MGM)节点:这类节点的作用是管理MySQL Cluster内的其他节点,如提供配置数据、启动并停止节点、运行备份等。由于这类节点负责管理其他节点的配置,应在启动其他节点之前首先启动这类节点。MGM节点是用命令“ndb_mgmd”启动的。管理服务器(MGM节点)负责管理 Cluster配置文件和 Cluster日志。
Cluster中的每个节点从管理服务器检索配置数据,并请求确定管理服务器所在位置的方式。当数据节点内出现新的事件时,节点将关于这类事件的信息传输到管理服务器,然后,将这类信息写入 Cluster日志。

数据节点:这类节点用于保存 Cluster的数据。数据节点的数目与副本的数目相关,是片段的倍数。例如,对于两个副本,每个副本有两个片段,那么就有4个数据节点。不过没有必要设置多个副本。数据节点是用命令“ndbd”启动的。各个数据节点之间相互复制数据,任何一个节点发送故障,始终会有另外的数据节点存储数据。

SQL节点:这是用来访问 Cluster数据的节点。对于MySQL Cluster,客户端节点是使用NDB Cluster存储引擎的传统MySQL服务器。通常,SQL节点是使用命令“mysqld –ndbcluster”启动的,或将“ndbcluster”添加到“my.cnf”后使用“mysqld”启动。

1个SQL Node就是一个使用NDB引擎的mysql server进程,用于供外部应用提供集群数据的访问入口。Data Node:用于存储集群数据;系统会尽量将数据放在内存中。
任何一个sql节点都是连接到所有存储节点上的,所以当一个存储节点发生故障时,sql节点可以将请求转移到另一个存储节点上执行。
MySQL_第32张图片

4.MySQL的一些操作

ps:设置主键自增:auto_increment

0.1 启动mysql服务
mysqld

0.1 关闭mysql服务,使用mysqladmin工具
mysqladmin -u root -p shutdown

1.查询表的状态,如存储引擎,列信息
show table status from test where name=‘t3’ \g

2.查询mysql支持的引擎
show engines

3.查看当前登录用户
select current_user()

4.查询数据库的字符集
show variables like ‘cahr%’;

5.查询表结构
desc tablename

6.刷新用户权限缓冲区
flush privileges;

由于用户权限信息量比较小,访问比较频繁,mysql在启动后会将权限表信息缓存起来,所以手工的修改权限表后,都需要执行flush privileges指令来重新刷新缓冲区。用户使用grant,revoke,drop user,create user 命令修改用户权限信息时,会自动刷新权限信息。
这里执行flush命令,需要reload权限

7.root用户密码丢失,怎么办?
(1)以不加载权限判断的方式启动:
mysqld --skip-grant-tables
(2)以root用户登录:
mysql -u root
(3)修改用户密码:(这里方式比较多)
update mysql.user set Password=password(‘root’) where user=‘root’ and host=‘localhost’;
(4)关闭mysql服务器,重新使用正常方式启动。这是root用户密码就已经更改了。

8.用户授权
grant select,insert on . to ‘test3’@‘localhost’ identified by ‘test3’;

如果需要给用户test3授予能够在所有主机上的权限,则可用通配符%,如:
grant select,insert on . to ‘test3’@’%’ identified by ‘test3’;

如果需要让用户也可以授予,则在授予权限时,可加上 with grant option,这种命令需要由root帐号执行。
grant all on test.* to ‘test’@‘localhost’ with grant option;

注意:好像有时候在授权时,使用%给所有主机都授权,但是使用localhost主机登录时,还是不行,需要单独给localhost授权。
好像有时候在授权并创建用户时,创建了针对所用主机登录时的密码,但是使用localhost主机登录时,提示密码不对,还是不行,需要单独给localhost登录设置密码。
这两是在phpadmin5.6.2版本中进行测试的结果。

9.root用户修改别人的密码
set password for ‘user’@‘localhost’ =password(‘userpassword’);

自己修改自己的密码:
set password=password(‘newpassword’);

10.查看用户的权限
show grants for ‘test’@‘localhost’;(不需要特殊帐号)

11.查看系统上的数据库列表
SHOW DATABASES ;(需要有 showdababase权限)
11.1 查看数据库中的表(需要先选择数据库)
show tables;
11.2 查询表结构
desc tablename

12.将文件中的数据装载到表中
load data infile ‘D:/txt.txt’ into table t5;
需要执行用户有file权限,且对文件有读权限。(默认当前的路径为当前数据库存储路径)
(注意文件的编译方式,实验时,如果直接是在windows下编写的普通文件,则读写的内容不是很匹配)

13.查看当前登录用户正在处理的命令
show processlist;(需要有process权限)
注意:只有有process权限,也能看到root用户正在执行的命令。关于正在二字的意义是:当你查询时,用户已经提交的,还没执行完的命令(一般的命令都是很快就能结束,一般显示不了,除非命令被阻塞了)。
如:test6用户锁住了user表,然后root用户登录,修改密码,执行set password=password(‘root’)命令,因为A锁住了user表,所以root用户修改密码的密码会被阻塞。这时,test用户登录执行show processlist就能看到root用户提交的命令:

当test6释放锁了之后,root用户的的命令能里面完成,test在使用show processlist则就看不到什么东西了

14.锁住表,释放锁
lock table user read,db write ;

unlock tables;

15.杀死用户线程
kill id ;需要有super权限
如test,test6用户同时登录到mysql.
test执行kill命令,杀死test6用户线程

之后,test6用户执行sql操作:

就能看到已经连不上了,需要退出重新登录。

16.回收用户的所有权限
revoke all privileges on . from ‘test’@‘localhost’;
mysql在这里是存在漏洞:如果使用了多条语句给用户授权了,在revoke all的时候,只会撤销一条授权语句,如:

使用了三次授权语句为用户授权:

revoke all之后:还是会存在其他的权限:

这时test还是具有mysql,test数据的权限,因此,在使用revoke all时一定要确保此时该用户没有其他授权条目了!

17.查询数据库中的表
show tables;

18.开启查询缓存
mysqld --query_cache_type=1 ;使mysql服务器已支持查询缓存的方式启动
查询当前查询缓存状态:
select @@query_cache_type;
关闭查询缓存:
set session query_cache_type=off;

19.查询系统变量query_cache_size的大小(数据库分配给查询缓存的内存大小)
select @@global.query_cache_size;

设置该参数:
set @@global.query_cache_size=1024000;

20.查询查询缓存的最大值
select @@global.query_cache_limit;

21.查询mysql的一些系统变量(环境变量,配置的值)
show variables;
使用时,最后加上限制,如show variables like ‘%innodb%’ ,因为变量全集太多

22.查询数据库是否支持分区
show variables like ‘%partition%’

23.分区表创建
创建range分区:
create table emp(no varchar(20) not null,name varchar(20),salary int )
partition by range(salary)
(
partition p1 values less than (1000),
partition p2 values less than (2000),
partition p3 values less than maxvalue
);

删除分区:ALTER TABLE emp DROP PARTITION p2

24.创建索引
CREATE INDEX mytable_categoryid
 ON mytable (category_id,category_id2 …);
例如:CREATE INDEX mytable_categoryid_userid ON mytable (category_id,user_id);

25 临时表
临时表再断开于mysql的连接后系统会自动删除临时表中的数据,但是这只限于用下面语句建立的表:
CREATE TEMPORARY TABLE tmp_table (
name VARCHAR(10) NOT NULL,
value INTEGER NOT NULL )
2)直接将查询结果导入临时表
CREATE TEMPORARY TABLE tmp_table SELECT * FROM table_name

  1. 另外mysql也允许你在内存中直接创建临时表,因为是在内存中所有速度会很快,语法如下:

CREATE TEMPORARY TABLE tmp_table (
name VARCHAR(10) NOT NULL,
value INTEGER NOT NULL
) TYPE = HEAP

27 mysql的FLUSH句法
如果你想要清除一些MySQL使用内部缓存,你应该使用FLUSH命令。为了执行FLUSH,你必须有reload权限。
flush_option可以是下列任何东西:

HOSTS:
这个用的最多,经常碰见。主要是用来清空主机缓存表。如果你的某些主机改变IP数字,或如果你得到错误消息Host … isblocked,你应该清空主机表。当在连接MySQL服务器时,对一台给定的主机有多于 max_connect_errors个错误连续不断地发生,MySQL为了安全的需要将会阻止该主机进一步的连接请求。清空主机表允许主机再尝试连接。

LOGS:
关闭当前的二进制日志文件并创建一个新文件,新的二进制日志文件的名字在当前的二进制文件的编号上加1。

PRIVILEGES:
这个也是经常使用的,每当重新赋权后,为了以防万一,让新权限立即生效,一般都执行一把,目地是从数据库授权表中重新装载权限到缓存中。

TABLES:
关闭所有打开的表,同时该操作将会清空查询缓存中的内容。

FLUSH TABLES WITH READ LOCK:
关闭所有打开的表,同时对于所有数据库中的表都加一个读锁,直到显示地执行unlock tables,该操作常常用于数据备份的时候。

STATUS:
重置大多数状态变量到0。

MASTER:
删除所有的二进制日志索引文件中的二进制日志文件,重置二进制日志文件的索引文件为空,创建一个新的二进制日志文件,不过这个已经不推荐使用,改成reset master 了。可以想象,以前自己是多土啊,本来一条简单的命令就可以搞定的,却要好几条命令来,以前的做法是先查出来当前的二进制日志文件名,再用purge 操作。

QUERY CACHE:
重整查询缓存,消除其中的碎片,提高性能,但是并不影响查询缓存中现有的数据,这点和Flush table 和Reset Query Cache(将会清空查询缓存的内容)不一样的。

SLAVE:
类似于重置复制吧,让从数据库忘记主数据库的复制位置,同时也会删除已经下载下来的relay log,与Master一样,已经不推荐使用,改成Reset Slave了。这个也很有用的。

一般来讲,Flush操作都会记录在二进制日志文件中,但是FLUSH LOGS、FLUSH MASTER、FLUSH SLAVE、FLUSH TABLES WITH READ LOCK不会记录,因此上述操作如果记录在二进制日志文件中话,会对从数据库造成影响。注意:Reset操作其实扮演的是一个Flush操作的增强版的角色。

5.其他

5.1字符编码问题

查看数据库字符编码:

show variables like “char%”
MySQL_第33张图片

修改字符编码

方式一:命令方式
set character_set_client=utf8;
set character_set_connection=utf8;
set character_set_database=utf8;
set character_set_results=utf8;
set character_set_server=utf8;
set character_set_system=utf8;
set collation_connection=utf8;
set collation_database=utf8;
set collation_server=utf8;

1.修改数据库字符集
alter database mini default character set = gb2312;
2.创建数据库设置字符集
create database mydb character set gb2312;
3.修改数据表的字符集
alter table pub_logs default character set = gb2312;
alter table pub_logs convert to character set gb2312;

方式二:修改配置文件
在windows系统下
1、在mysql的安装目录下找到my.ini文件(如果没有的话就把my-medium.ini复制,然后重命名为my.ini即可)
2、在my.ini文件中找到[client]和[mysqld]字段,在下面均加上default-character-set=utf8,保存并关闭
3、重启mysql服务

在linux系统下
1、打开配置文件,我使用的linux版本是ubuntu,配置文件在/etc/mysql/my.cnf
2、在[client]和[mysqld]字段下面均添加default-character-set=utf8,保存并关闭
3、重启mysql服务

注意:
如果重启成功,并查看数据库编码,如果结果如下
如果在linux下重启mysql服务的时候出现Job failed to start,在window下重启失败,这是因为你安装了高版本的mysql(mysql5.5以上),在高版本对字符编码方式修改的办法中,在[mysqld]下的修改发生了变化,正确方式如下:
[mysqld]下添加的应该为:
character-set-server=utf8
collation-server=utf8_general_ci
重启mysql,现在再次查看字符编码,如果跟下面一致,说明成功了

5.2 SQL执行顺序问题

sql语法的分析是从右到左

sql语句的执行步骤:

1)语法分析,分析语句的语法是否符合规范,衡量语句中各表达式的意义。
2)语义分析,检查语句中涉及的所有数据库对象是否存在,且用户有相应的权限。
3)视图转换,将涉及视图的查询语句转换为相应的对基表查询语句。
4)表达式转换, 将复杂的 SQL 表达式转换为较简单的等效连接表达式。
5)选择优化器,不同的优化器一般产生不同的“执行计划”
6)选择连接方式, ORACLE 有三种连接方式,对多表连接 ORACLE 可选择适当的连接方式。
7)选择连接顺序, 对多表连接 ORACLE 选择哪一对表先连接,选择这两表中哪个表做为源数据表。
8)选择数据的搜索路径,根据以上条件选择合适的数据搜索路径,如是选用全表搜索还是利用索引或是其他的方式。
9)运行“执行计划”

SQL Select语句完整的执行顺序:

1、from子句组装来自不同数据源的数据;
2、where子句基于指定的条件对记录行进行筛选;
3、group by子句将数据划分为多个分组;
4、使用聚集函数进行计算;
5、使用having子句筛选分组;
6、计算所有的表达式;
7、select 的字段;

8、使用order by对结果集进行排序。

SQL语言不同于其他编程语言的最明显特征是处理代码的顺序。在大多数据库语言中,代码按编码顺序被处理。但在SQL语句中,第一个被处理的子句式FROM,而不是第一出现的SELECT。

5.3 MySQL内存的使用说明(全局缓存+线程缓存)

全局缓存

**key_buffer_size:**决定索引处理的速度,尤其是索引读的速度。默认值是16M,通过检查状态值Key_read_requests和Key_reads,可以知道key_buffer_size设置是否合理。比例key_reads / key_read_requests应该尽可能的低,至少是1:100,1:1000更好(上述状态值可以使用’key_read%'获得用来显示状态数据)。key_buffer_size只对MyISAM表起作用。即使你不使用MyISAM表,但是内部的临时磁盘表是MyISAM表,也要使用该值。可以使用检查状态值’created_tmp_disk_tables’得知详情。

**innodb_buffer_pool_size:**InnoDB使用该参数指定大小的内存来缓冲数据和索引,这个是Innodb引擎中影响性能最大的参数。

**innodb_additional_mem_pool_size:**指定InnoDB用来存储数据字典和其他内部数据结构的内存池大小。缺省值是8M。通常不用太大,只要够用就行,应该与表结构的复杂度有关系。如果不够用,MySQL会在错误日志中写入一条警告信息。

**innodb_log_buffer_size:**指定InnoDB用来存储日志数据的缓存大小,如果您的表操作中包含大量并发事务(或大规模事务),并且在事务提交前要求记录日志文件,请尽量调高此项值,以提高日志效率。

**query_cache_size:**是MySQL的查询缓冲大小。(从4.0.1开始,MySQL提供了查询缓冲机制)使用查询缓冲,MySQL将SELECT语句和查询结果存放在缓冲区中,今后对于同样的SELECT语句(区分大小写),将直接从缓冲区中读取结果。根据MySQL用户手册,使用查询缓冲最多可以达到238%的效率。通过检查状态值’Qcache_%’,可以知道query_cache_size设置是否合理:如果Qcache_lowmem_prunes的值非常大,则表明经常出现缓冲不够的情况,如果Qcache_hits的值也非常大,则表明查询缓冲使用非常频繁,此时需要增加缓冲大小;如果Qcache_hits的值不大,则表明你的查询重复率很低,这种情况下使用查询缓冲反而会影响效率,那么可以考虑不用查询缓冲。此外,在SELECT语句中加入SQL_NO_CACHE可以明确表示不使用查询缓冲。

线程缓存

每个连接到MySQL服务器的线程都需要有自己的缓冲。大概需要立刻分配256K,甚至在线程空闲时,它们使用默认的线程堆栈,网络缓存等。事务开始之后,则需要增加更多的空间。运行较小的查询可能仅给指定的线程增加少量的内存消耗,然而如果对数据表做复杂的操作例如扫描、排序或者需要临时表,则需分配大约read_buffer_size,sort_buffer_size,read_rnd_buffer_size,tmp_table_size大小的内存空间。不过它们只是在需要的时候才分配,并且在那些操作做完之后就释放了。有的是立刻分配成单独的组块。tmp_table_size 可能高达MySQL所能分配给这个操作的最大内存空间了。

**read_buffer_size:**是MySQL读入缓冲区大小。对表进行顺序扫描的请求将分配一个读入缓冲区,MySQL会为它分配一段内存缓冲区。read_buffer_size变量控制这一缓冲区的大小。如果对表的顺序扫描请求非常频繁,并且你认为频繁扫描进行得太慢,可以通过增加该变量值以及内存缓冲区大小提高其性能。

**sort_buffer_size:**是MySQL执行排序使用的缓冲大小。如果想要增加ORDER BY的速度,首先看是否可以让MySQL使用索引而不是额外的排序阶段。如果不能,可以尝试增加sort_buffer_size变量的大小。

**read_rnd_buffer_size:**是MySQL的随机读缓冲区大小。当按任意顺序读取行时(例如,按照排序顺序),将分配一个随机读缓存区。进行排序查询时,MySQL会首先扫描一遍该缓冲,以避免磁盘搜索,提高查询速度,如果需要排序大量数据,可适当调高该值。但MySQL会为每个客户连接发放该缓冲空间,所以应尽量适当设置该值,以避免内存开销过大。

**tmp_table_size:**是MySQL的临时表缓冲大小。所有联合在一个DML指令内完成,并且大多数联合甚至可以不用临时表即可以完成。大多数临时表是基于内存的(HEAP)表。具有大的记录长度的临时表 (所有列的长度的和)或包含BLOB列的表存储在硬盘上。如果某个内部heap(堆积)表大小超过tmp_table_size,MySQL可以根据需要自动将内存中的heap表改为基于硬盘的MyISAM表。还可以通过设置tmp_table_size选项来增加临时表的大小。也就是说,如果调高该值,MySQL同时将增加heap表的大小,可达到提高联接查询速度的效果。

**thread_stack :**主要用来存放每一个线程自身的标识信息,如线程id,线程运行时基本信息等等,我们可以通过 thread_stack 参数来设置为每一个线程栈分配多大的内存。

**join_buffer_size:**应用程序经常会出现一些两表(或多表)Join的操作需求,MySQL在完成某些 Join 需求的时候(all/index join),为了减少参与Join的“被驱动表”的读取次数以提高性能,需要使用到 Join Buffer 来协助完成 Join操作。当 Join Buffer 太小,MySQL 不会将该 Buffer 存入磁盘文件,而是先将Join Buffer中的结果集与需要 Join 的表进行 Join 操作,然后清空 Join Buffer 中的数据,继续将剩余的结果集写入此 Buffer 中,如此往复。这势必会造成被驱动表需要被多次读取,成倍增加 IO 访问,降低效率。

**binlog_cache_size:**在事务过程中容纳二进制日志SQL 语句的缓存大小。二进制日志缓存是服务器支持事务存储引擎并且服务器启用了二进制日志(—log-bin 选项)的前提下为每个客户端分配的内存,注意,是每个Client 都可以分配设置大小的binlog cache 空间。如果系统中经常会出现多语句事务的话,可以尝试增加该值的大小,以获得更好的性能。当然,我们可以通过MySQL 的以下两个状态变量来判断当前的binlog_cache_size 的状况:Binlog_cache_use 和Binlog_cache_disk_use。“max_binlog_cache_size”:和"binlog_cache_size"相对应,但是所代表的是binlog 能够使用的最大cache 内存大小。当我们执行多语句事务的时候,max_binlog_cache_size 如果不够大的话,系统可能会报出“ Multi-statement transaction required more than ‘max_binlog_cache_size’ bytes ofstorage”的错误。
其中需要注意的是:table_cache表示的是所有线程打开的表的数目,和内存无关。

5.4 Innodb

InnoDB存储引擎的三个关键特性:插入缓冲(insert buffer)、二次写(double write)、自适应哈希索引(adaptive hash index)。

5.4.1、插入缓冲(insert buffer)的原理:

对于非聚集索引的插入和更新,不是每一次直接插入索引页中,而是首先判断插入的非聚集索引页是否在缓冲池中,如果在,则直接插入,否则,先放入一个插入缓冲区中。好似欺骗数据库这个非聚集的索引已经插入到叶子节点了,然后再以一定的频率执行插入缓冲和非聚集索引页子节点的合并操作,这时通常能将多个插入合并到一个操作中,这就大大提高了对非聚集索引执行插入和修改操作的性能。

插入缓冲使用的条件:

1、索引是辅助索引;

2、索引不是唯一的;
特点:写缓存区,避免单次插入就理解读磁盘(插入缓冲对查询语句没有任何帮助)

5.4.2 两次写(double write)

两次写给innodb带来的是可靠性,主要用来解决部分写失败(partial page write)。doublewrite有两部分组成,一部分是内存中的doublewrite buffer,大小为2M,另外一部分就是物理磁盘上的共享表空间中连续的128个页,即两个区,大小同样为2M。当缓冲池的脏业刷新时,并不直接写硬盘,而是通过memcpy函数将脏页先拷贝到内存中的doublewrite buffer,之后通过doublewrite buffer再分两次写,每次写入1M到共享表空间的物理磁盘上,然后马上调用fsync函数,同步磁盘。如下图所示
MySQL_第34张图片

以下命令可以查看doublewrite的使用 情况。

mysql> show global status like ‘innodb_dblwr%’;

slave上可以通过设置skip_innodb_doublewrite参数关闭两次写功能来提高性能,但是master上一定要开启此功能,保证数据 安全。

自适应哈希索引(adaptive hash index)

**由于innodb不支持hash索引,**但是在某些情况下hash索引的效率很高,于是出现了 adaptive hash index功能,innodb存储引擎会监控对表上索引的查找,如果观察到建立hash索引可以提高性能的时候,则自动建立hash索引。可以通过 show engine innodb status\G来查看自适应哈希索引的使用情况。可以使用innodb_adaptive_hash_index来禁用和启用hash索引,默认开启。

你可能感兴趣的:(存储,数据库)