扫二维码与项目经理沟通
我们在微信上24小时期待你的声音
解答本文疑问/技术咨询/运营咨询/技术建议/互联网交流
云运维涉及的方面比较广,基础知识仍然是必不可少:Linux基础,基本linux命令的使用,Shell脚本编程,Linux操作系统知识(Ubuntu,CentOS系统等)。
目前创新互联公司已为上千家的企业提供了网站建设、域名、雅安服务器托管、网站托管维护、企业网站设计、富顺网站维护等服务,公司将坚持客户导向、应用为本的策略,正道将秉承"和谐、参与、激情"的文化,与客户和合作伙伴齐心协力一起成长,共同发展。
了解完基础知识后,可以给自己确定下方向:
1、大数据方向: 涉及Hadoop(hdfs,yarn等),spark,hbase,hive,storm等知识
2、虚拟化技术:openstack,kvm,nova,docker,vmware,xen等
3、应用:mysql,redis,memcached,sqlserver
4、对目前的云提供商的业务的了解:阿里云,腾讯云,京东云,金山云,AWS等
5、脚本开发(DevOps必备):python,ruby
6、比较常用的运维工具:jenkins,chef,puppet,ansible等
1、InnoDB存储引擎
Mysql版本=5.5 默认的存储引擎,MySQL推荐使用的存储引擎。支持事务,行级锁定,外键约束。事务安全型存储引擎。更加注重数据的完整性和安全性。
存储格式 : 数据,索引集中存储,存储于同一个表空间文件中。
InnoDB的行锁模式及其加锁方法: InnoDB中有以下两种类型的行锁:共享锁(读锁: 允许事务对一条行数据进行读取)和 互斥锁(写锁: 允许事务对一条行数据进行删除或更新), 对于update,insert,delete语句,InnoDB会自动给设计的数据集加互斥锁,对于普通的select语句,InnoDB不会加任何锁。
InnoDB行锁的实现方式: InnoDB行锁是通过给索引上的索引项加锁来实现的,如果没有索引,InnoDB将通过隐藏的聚簇索引来对记录加锁。InnoDB这种行锁实现特点意味着:如果不通过索引条件检索数据,那么InnoDB将对表中的所有记录加锁,实际效果跟表锁一样。
(1)在不通过索引条件查询时,InnoDB会锁定表中的所有记录。
(2)Mysql的行锁是针对索引加的锁,不是针对记录加的锁,所以虽然是访问不同行的记录,但是如果使用相同的索引键,是会出现冲突的。
(3)当表有多个索引的时候,不同的事务可以使用不同的索引锁定不同的行,但都是通过行锁来对数据加锁。
优点:
1、支持事务处理、ACID事务特性;
2、实现了SQL标准的四种隔离级别( 原子性( Atomicity )、一致性( Consistency )、隔离性(Isolation )和持续性(Durability ));
3、支持行级锁和外键约束;
4、可以利用事务日志进行数据恢复。
5、锁级别为行锁,行锁优点是适用于高并发的频繁表修改,高并发是性能优于 MyISAM。缺点是系统消耗较大。
6、索引不仅缓存自身,也缓存数据,相比 MyISAM 需要更大的内存。
缺点:
因为它没有保存表的行数,当使用COUNT统计时会扫描全表。
使用场景:
(1)可靠性要求比较高,或者要求事务;(2)表更新和查询都相当的频繁,并且表锁定的机会比较大的情况。
2、 MyISAM存储引擎
MySQL= 5.5 MySQL默认的存储引擎。ISAM:Indexed Sequential Access Method(索引顺序存取方法)的缩写,是一种文件系统。擅长与处理,高速读与写。
功能:
(1)支持数据压缩存储,但压缩后的表变成了只读表,不可写;如果需要更新数据,则需要先解压后更新。
(2)支持表级锁定,不支持高并发;
(3)支持并发插入。写操作中的插入操作,不会阻塞读操作(其他操作);
优点:
1.高性能读取;
2.因为它保存了表的行数,当使用COUNT统计时不会扫描全表;
缺点:
1、锁级别为表锁,表锁优点是开销小,加锁快;缺点是锁粒度大,发生锁冲动概率较高,容纳并发能力低,这个引擎适合查询为主的业务。
2、此引擎不支持事务,也不支持外键。
3、INSERT和UPDATE操作需要锁定整个表;
使用场景:
(1)做很多count 的计算;(2)插入不频繁,查询非常频繁;(3)没有事务。
InnoDB和MyISAM一些细节上的差别:
1、InnoDB不支持FULLTEXT类型的索引,MySQL5.6之后已经支持(实验性)。
2、InnoDB中不保存表的 具体行数,也就是说,执行select count() from table时,InnoDB要扫描一遍整个表来计算有多少行,但是MyISAM只要简单的读出保存好的行数即可。注意的是,当count()语句包含 where条件时,两种表的操作是一样的。
3、对于AUTO_INCREMENT类型的字段,InnoDB中必须包含只有该字段的索引,但是在MyISAM表中,可以和其他字段一起建立联合索引。
4、DELETE FROM table时,InnoDB不会重新建立表,而是一行一行的删除。
5、LOAD TABLE FROM MASTER操作对InnoDB是不起作用的,解决方法是首先把InnoDB表改成MyISAM表,导入数据后再改成InnoDB表,但是对于使用的额外的InnoDB特性(例如外键)的表不适用。
6、另外,InnoDB表的行锁也不是绝对的,如果在执行一个SQL语句时MySQL不能确定要扫描的范围,InnoDB表同样会锁全表。
1.索引概述
利用关键字,就是记录的部分数据(某个字段,某些字段,某个字段的一部分),建立与记录位置的对应关系,就是索引。索引的关键字一定是排序的。索引本质上是表字段的有序子集,它是提高查询速度最有效的方法。一个没有建立任何索引的表,就相当于一本没有目录的书,在每次查询时就会进行全表扫描,这样会导致查询效率极低、速度也极慢。如果建立索引,那么就好比一本添加的目录,通过目录的指引,迅速翻阅到指定的章节,提升的查询性能,节约了查询资源。
2.索引种类
从索引的定义方式和用途中来看:主键索引,唯一索引,普通索引,全文索引。
无论任何类型,都是通过建立关键字与位置的对应关系来实现的。索引是通过关键字找对应的记录的地址。
以上类型的差异:对索引关键字的要求不同。
关键字:记录的部分数据(某个字段,某些字段,某个字段的一部分)。
普通索引,index:对关键字没有要求。
唯一索引,unique index:要求关键字不能重复。同时增加唯一约束。
主键索引,primary key:要求关键字不能重复,也不能为NULL。同时增加主键约束。
全文索引,fulltext key:关键字的来源不是所有字段的数据,而是从字段中提取的特别关键词。
PS:这里主键索引和唯一索引的区别在于:主键索引不能为空值,唯一索引允许空值;主键索引在一张表内只能创建一个,唯一索引可以创建多个。主键索引肯定是唯一索引,但唯一索引不一定是主键索引。
3.索引原则
如果索引不遵循使用原则,则可能导致索引无效。
(1)列独立
如果需要某个字段上使用索引,则需要在字段参与的表达中,保证字段独立在一侧。否则索引不会用到索引, 例如这条sql就不会用到索引:select * from A where id+1=10;
(2)左原则
Like:匹配模式必须要左边确定不能以通配符开头。例如:select * from A where name like '%小明%' ,不会用到索引,而select * from A where name like '小明%' 就可以用到索引(name字段有建立索引),如果业务上需要用到'%小明%'这种方式,有两种方法:1.可以考虑全文索引,但mysql的全文索引不支持中文;2.只查询索引列或主键列,例如:select name from A where name like '%小明%' 或 select id from A where name like '%小明%' 或 select id,name from A where name like '%小明%' 这三种情况都会用到name的索引;
复合索引:一个索引关联多个字段,仅仅针对左边字段有效果,添加复合索引时,第一个字段很重要,只有包含第一个字段作为查询条件的情况才会使用复合索引(必须用到建索引时选择的第一个字段作为查询条件,其他字段的顺序无关),而且查询条件只能出现and拼接,不能用or,否则则无法使用索引.
(3)OR的使用
必须要保证 OR 两端的条件都存在可以用的索引,该查询才可以使用索引。
(4)MySQL智能选择
即使满足了上面说原则,MySQL也能弃用索引,例如:select * from A where id 1;这里弃用索引的主要原因:查询即使使用索引,会导致出现大量的随机IO,相对于从数据记录的第一条遍历到最后一条的顺序IO开销,还要大。
4.索引的使用场景
(1)索引检索:检索数据时使用索引。
(2)索引排序: 如果order by 排序需要的字段上存在索引,则可能使用到索引。
(3)索引覆盖: 索引拥有的关键字内容,覆盖了查询所需要的全部数据,此时,就不需要在数据区获取数据,仅仅在索引区即可。覆盖就是直接在索引区获取内容,而不需要在数据区获取。例如: select name from A where name like '小明%';
建立索引索引时,不能仅仅考虑where检索,同时考虑其他的使用场景。(在所有的where字段上增加索引,就是不合理的)
5.前缀索引
前缀索引是建立索引关键字一种方案。通常会使用字段的整体作为索引关键字。有时,即使使用字段前部分数据,也可以去识别某些记录。就比如一个班级里,我要找王xx,假如姓王的只有1个人,那么就可以建一个关键字为'王'的前缀索引。语法:Index `index_name` (`index_field`(N))使用index_name前N个字符建立的索引。
6.索引失效
(1) 应尽量避免在 where 子句中使用 != 或 操作符,否则将引擎放弃使用索引而进行全表扫描;
(2) 应尽量避免在 where 子句中使用 or 来连接条件,如果一个字段有索引,一个字段没有索引,将导致引擎放弃使用索引而进行全表扫描;
(3) 应尽量避免在 where 子句中对字段进行 null 值判断,否则将导致引擎放弃使用索引而进行全表扫描;
(4)应尽量避免在 where 子句中对字段进行表达式操作,这将导致引擎放弃使用索引而进行全表扫描;如select id from t where num/2 = 100;
(5) 应尽量避免在where子句中对字段进行函数操作,这将导致引擎放弃使用索引而进行全表扫描;如:select id from t where substring(name,1,3) = ’abc’ ;
(6)应尽量避免在where子句中对字段进行类型转换,这将导致引擎放弃使用索引而进行全表扫描; 如果列类型是字符串,那一定要在条件中将数据使用引号引用起来,如select id from t where id = 1;如果id字段在表设计中是varchar类型,那么即使id列上存的是数字,在查询时也一定要用varchar去匹配,sql应改为select id from t where id = '1';
(7)应尽量避免在where子句中单独引用复合索引里非第一位置的索引;
join 的两种算法:BNL 和 NLJ
NLJ(Nested Loop Join)嵌套循环算法;以如下 SQL 为例:
select * from t1 join t2 on t1.a=t2.a
SQL 执行时内部流程是这样的:
1. 先从 t1(假设这里 t1 被选为驱动表)中取出一行数据 X;
2. 从 X 中取出关联字段 a 值,去 t2 中进行查找,满足条件的行取出;
3. 重复1、2步骤,直到表 t1 最后一行循环结束。
这就是一个嵌套循环的过程,如果在被驱动表上查找数据时可以使用索引,总的对比计算次数等于驱动表满足 where 条件的行数。假设这里 t1、t2都是1万行,则只需要 1万次计算,这里用到的是Index Nested-Loops Join(INLJ,基于索引的嵌套循环联接)。
如果 t1、t2 的 a 字段都没有索引,还按照上述的嵌套循环流程查找数据呢?每次在被驱动表上查找数据时都是一次全表扫描,要做1万次全表扫描,扫描行数等于 1万+1万*1万,这个效率很低,如果表行数更多,扫描行数动辄几百亿,所以优化器肯定不会使用这样的算法,而是选择 BNL 算法;
BNLJ(Block Nested Loop Join)块嵌套循环算法;
1. 把 t1 表(假设这里 t1 被选为驱动表)满足条件的数据全部取出放到线程的 join buffer 中;
2. 每次取 t2 表一行数据,去 joinbuffer 中进行查找,满足条件的行取出,直到表 t2 最后一行循环结束。
这个算法下,执行计划的 Extra 中会出现 Using join buffer(Block Nested Loop),t1、t2 都做了一次全表扫描,总的扫描行数等于 1万+1万。但是由于 joinbuffer 维护的是一个无序数组,每次在 joinbuffer 中查找都要遍历所有行,总的内存计算次数等于1万*1万。另外如果 joinbuffer 不够大放不下驱动表的数据,则要分多次执行上面的流程,会导致被驱动表也做多次全表扫描。
BNLJ相对于NLJ的优点在于,驱动层可以先将部分数据加载进buffer,这种方法的直接影响就是将大大减少内层循环的次数,提高join的效率。
例如:
如果内层循环有100条记录,外层循环也有100条记录,这样的话,每次外层循环先将10条记录放到buffer中,内层循环的100条记录每条与这个buffer中的10条记录进行匹配,只需要匹配内层循环总记录数次即可结束一次循环(在这里,即只需要匹配100次即可结束),然后将匹配成功的记录连接后放入结果集中,接着,外层循环继续向buffer中放入10条记录,同理进行匹配,并将成功的记录连接后放入结果集。后续循环以此类推,直到循环结束,将结果集发给client为止。
可以发现,若用NLJ,则需要100 * 100次才可结束,BNLJ则需要100 / block_size * 100 = 10 * 100次就可结束,大大减少了循环次数。
JOIN 按照功能大致分为如下三类:
JOIN、STRAIGHT_JOIN、INNER JOIN(内连接,或等值连接):取得两个表中存在连接匹配关系的记录。
LEFT JOIN(左连接):取得左表(table1)完全记录,即是右表(table2)并无对应匹配记录。
RIGHT JOIN(右连接):与 LEFT JOIN 相反,取得右表(table2)完全记录,即是左表(table1)并无匹配对应记录。
注意:mysql不支持Full join,不过可以通过UNION 关键字来合并 LEFT JOIN 与 RIGHT JOIN来模拟FULL join。
mysql 多表连接查询方式,因为mysql只支持NLJ算法,所以如果是小表驱动大表则效率更高;反之则效率下降;因此mysql对内连接或等值连接的方式做了一个优化,会去判断join表的数据行大小,然后取数据行小的表为驱动表。
INNER JOIN、JOIN、WHERE等值连接和STRAIGHT_JOIN都能表示内连接,那平时如何选择呢?一般情况下用INNER JOIN、JOIN或者WHERE等值连接,因为MySQL 会按照"小表驱动大表的策略"进行优化。当出现需要排序时,才考虑用STRAIGHT_JOIN指定某张表为驱动表。
两表JOIN优化
a.当无order by条件时,根据实际情况,使用left/right/inner join即可,根据explain优化 ;
b.当有order by条件时,如select * from a inner join b where 1=1 and other condition order by a.col;使用explain解释语句;
1)如果第一行的驱动表为a,则效率会非常高,无需优化;
2)否则,因为只能对驱动表字段直接排序的缘故,会出现using temporary,所以此时需要使用STRAIGHT_JOIN明确a为驱动表,来达到使用a.col上index的优化目的;或者使用left join且Where条件中不含b的过滤条件,此时的结果集为a的全集,而STRAIGHT_JOIN为inner join且使用a作为驱动表。注:使用STRAIGHT_JOIN虽然不会using temporary,但也不是一定就能提高效率,如果a表数据远远超过b表,那么有可能使用STRAIGHT_JOIN时比原来的sql效率更低,所以怎么使用STRAIGHT_JOIN,还是要视情况而定。
在使用left join(或right join)时,应该清楚的知道以下几点:
(1). on与 where的执行顺序
ON 条件(“A LEFT JOIN B ON 条件表达式”中的ON)用来决定如何从 B 表中检索数据行。如果 B 表中没有任何一行数据匹配 ON 的条件,将会额外生成一行所有列为 NULL 的数据,在匹配阶段 WHERE 子句的条件都不会被使用。仅在匹配阶段完成以后,WHERE 子句条件才会被使用。它将从匹配阶段产生的数据中检索过滤。
所以我们要注意:在使用Left (right) join的时候,一定要在先给出尽可能多的匹配满足条件,减少Where的执行。
(2).注意ON 子句和 WHERE 子句的不同
即使右表的数据不满足ON后面的条件,也会在结果集拼接一条为NULL的数据行,但WHERE后面的条件不一样,右表不满足WHERE的条件,左表关联的数据也会被过滤掉。
(3).尽量避免子查询,而用join
往往性能这玩意儿,更多时候体现在数据量比较大的时候,此时,我们应该避免复杂的子查询。
(1)in 和 not in 要慎用,如:select id from t where num in(1,2,3)对于连续的数值,能用 between 就不要用 in:select id from t where num between 1 and 3很多时候用 exists 代替 in 是一个好的选择:select num from a where num in(select num from b)用下面的语句替换:select num from a where exists(select 1 from b where num=a.num)
(2)Update 语句,如果只更改1、2个字段,不要Update全部字段,否则频繁调用会引起明显的性能消耗,同时带来大量日志。
(3)join语句,MySQL里面的join是用小表去驱动大表,而由于MySQL join实现的原理就是做循环,比如left join就是对左边的数据进行循环去驱动右边的表,左边有m条记录匹配,右边有n条记录那么就是做m次循环,每次扫描n行数据,总扫面行数是m*n行数据。左边返回的结果集的大小就决定了循环的次数,故单纯的用小表去驱动大表不一定的正确的,小表的结果集可能也大于大表的结果集,所以写join的时候尽可能的先估计两张表的可能结果集,用小结果集去驱动大结果集.值得注意的是在使用left/right join的时候,从表的条件应写在on之后,主表应写在where之后.否则MySQL会当作普通的连表查询;
(4)select count(*) from table;这样不带任何条件的count会引起全表扫描,并且没有任何业务意义,是一定要杜绝的;
(5)select * from t 这种语句要尽量避免,使用具体的字段代替*,更有实际意义,需要什么字段就返回什么字段;
(6)数据量大的情况下,limit要慎用,因为使用limit m,n方式分页时,mysql每次都是查询前m+n条,然后舍弃前m条,所以m越大,偏移量越大,性能就越差。比如:select * from A limit 1000000,20这钟,查询效率就会非常低,当分页的页数大于一定的数量之后,就可以换种方式来分页:select * from A a join (select id from A limit 1000000,20) b on a.id=b.id;
《MySQL是怎样运行的:从根儿上理解 MySQL》采用诙谐幽默的表达方式,对MySQL的底层运行原理进行了介绍,内容涵盖了使用MySQL的同学在求职面试和工作中常见的一些核心概念。总计22 章,划分为4个部分。第1部分介绍了MySQL入门的一些知识,比如MySQL的服务器程序和客户端程序有哪些、MySQL的启动选项和系统变量,以及使用的字符集等。第2部分是本书后续章节的基础,介绍了MySQL的一些基础知识,比如记录、页面、索引、表空间的结构和用法等。第3部分则与大家在工作中经常遇到的查询优化问题紧密相关,介绍了单表查询、连接查询的执行原理,MySQL基于成本和规则的优化具体指什么,并详细分析了Explain语句的执行结果。第4部分则是与MySQL中的事务和锁相关,介绍了事务概念的来源,MySQL是如何实现事务的,包括redo日志、undo日志、MVCC、各种锁的细节等。
尽管《MySQL是怎样运行的:从根儿上理解 MySQL》在写作时参考的MySQL源代码版本是5.7.22,但是大部分内容与具体的版本号并没有多大关系。无论是很早之前就已身居MySQL专家的人员,还是希望进一步提升技能的DBA,甚至是三五年后才会入行的“萌新”,本书都是他们彻底了解MySQL运行原理的优秀书
前言:
MYSQL 应该是最流行了 WEB 后端数据库。虽然 NOSQL 最近越来越多的被提到,但是相信大部分架构师还是会选择 MYSQL 来做数据存储。本文作者总结梳理MySQL性能调优的15个重要变量,又不足需要补充的还望大佬指出。
1.DEFAULT_STORAGE_ENGINE
如果你已经在用MySQL 5.6或者5.7,并且你的数据表都是InnoDB,那么表示你已经设置好了。如果没有,确保把你的表转换为InnoDB并且设置default_storage_engine为InnoDB。
为什么?简而言之,因为InnoDB是MySQL(包括Percona Server和MariaDB)最好的存储引擎 – 它支持事务,高并发,有着非常好的性能表现(当配置正确时)。这里有详细的版本介绍为什么
2.INNODB_BUFFER_POOL_SIZE
这个是InnoDB最重要变量。实际上,如果你的主要存储引擎是InnoDB,那么对于你,这个变量对于MySQL是最重要的。
基本上,innodb_buffer_pool_size指定了MySQL应该分配给InnoDB缓冲池多少内存,InnoDB缓冲池用来存储缓存的数据,二级索引,脏数据(已经被更改但没有刷新到硬盘的数据)以及各种内部结构如自适应哈希索引。
根据经验,在一个独立的MySQL服务器应该分配给MySQL整个机器总内存的80%。如果你的MySQL运行在一个共享服务器,或者你想知道InnoDB缓冲池大小是否正确设置,详细请看这里。
3.INNODB_LOG_FILE_SIZE
InnoDB重做日志文件的设置在MySQL社区也叫做事务日志。直到MySQL 5.6.8事务日志默认值innodb_log_file_size=5M是唯一最大的InnoDB性能杀手。从MySQL 5.6.8开始,默认值提升到48M,但对于许多稍繁忙的系统,还远远要低。
根据经验,你应该设置的日志大小能在你服务器繁忙时能存储1-2小时的写入量。如果不想这么麻烦,那么设置1-2G的大小会让你的性能有一个不错的表现。这个变量也相当重要,更详细的介绍请看这里。
当然,如果你有大量的大事务更改,那么,更改比默认innodb日志缓冲大小更大的值会对你的性能有一定的提高,但是你使用的是autocommit,或者你的事务更改小于几k,那还是保持默认的值吧。
4.INNODB_FLUSH_LOG_AT_TRX_COMMIT
默认下,innodb_flush_log_at_trx_commit设置为1表示InnoDB在每次事务提交后立即刷新同步数据到硬盘。如果你使用autocommit,那么你的每一个INSERT, UPDATE或DELETE语句都是一个事务提交。
同步是一个昂贵的操作(特别是当你没有写回缓存时),因为它涉及对硬盘的实际同步物理写入。所以如果可能,并不建议使用默认值。
两个可选的值是0和2:
* 0表示刷新到硬盘,但不同步(提交事务时没有实际的IO操作)
* 2表示不刷新和不同步(也没有实际的IO操作)
所以你如果设置它为0或2,则同步操作每秒执行一次。所以明显的缺点是你可能会丢失上一秒的提交数据。具体来说,你的事务已经提交了,但服务器马上断电了,那么你的提交相当于没有发生过。
显示的,对于金融机构,如银行,这是无法忍受的。不过对于大多数网站,可以设置为innodb_flush_log_at_trx_commit=0|2,即使服务器最终崩溃也没有什么大问题。毕竟,仅仅在几年前有许多网站还是用MyISAM,当崩溃时会丢失30s的数据(更不要提那令人抓狂的慢修复进程)。
那么,0和2之间的实际区别是什么?性能明显的差异是可以忽略不计,因为刷新到操作系统缓存的操作是非常快的。所以很明显应该设置为0,万一MySQL崩溃(不是整个机器),你不会丢失任何数据,因为数据已经在OS缓存,最终还是会同步到硬盘的。
5.SYNC_BINLOG
已经有大量的文档写到sync_binlog,以及它和innodb_flush_log_at_trx_commit的关系,下面我们来简单的介绍下:
a) 如果你的服务器没有设置从服务器,而且你不做备份,那么设置sync_binlog=0将对性能有好处。
b) 如果你有从服务器并且做备份,但你不介意当主服务器崩溃时在二进制日志丢失一些事件,那么为了更好的性能还是设置为sync_binlog=0.
c) 如果你有从服务器并且备份,你非常在意从服务器的一致性,以及能及时恢复到一个时间点(通过使用最新的一致性备份和二进制日志将数据库恢复到特定时间点的能力),那么你应该设置innodb_flush_log_at_trx_commit=1,并且需要认真考虑使用sync_binlog=1。
问题是sync_binlog=1代价比较高 – 现在每个事务也要同步一次到硬盘。你可能会想为什么不把两次同步合并成一次,想法正确 – 新版本的MySQL(5.6和5.7,MariaDB和Percona Server)已经能合并提交,那么在这种情况下sync_binlog=1的操作也不是这么昂贵了,但在旧的mysql版本中仍然会对性能有很大影响。
6.INNODB_FLUSH_METHOD
将innodb_flush_method设置为O_DIRECT以避免双重缓冲.唯一一种情况你不应该使用O_DIRECT是当你操作系统不支持时。但如果你运行的是Linux,使用O_DIRECT来激活直接IO。
不用直接IO,双重缓冲将会发生,因为所有的数据库更改首先会写入到OS缓存然后才同步到硬盘 – 所以InnoDB缓冲池和OS缓存会同时持有一份相同的数据。特别是如果你的缓冲池限制为总内存的50%,那意味着在写密集的环境中你可能会浪费高达50%的内存。如果没有限制为50%,服务器可能由于OS缓存的高压力会使用到swap。
简单地说,设置为innodb_flush_method=O_DIRECT。
7.INNODB_BUFFER_POOL_INSTANCES
MySQL 5.5引入了缓冲实例作为减小内部锁争用来提高MySQL吞吐量的手段。
在5.5版本这个对提升吞吐量帮助很小,然后在MySQL 5.6版本这个提升就非常大了,所以在MySQL5.5中你可能会保守地设置innodb_buffer_pool_instances=4,在MySQL 5.6和5.7中你可以设置为8-16个缓冲池实例。
你设置后观察会觉得性能提高不大,但在大多数高负载情况下,它应该会有不错的表现。
对了,不要指望这个设置能减少你单个查询的响应时间。这个是在高并发负载的服务器上才看得出区别。比如多个线程同时做许多事情。
8.INNODB_THREAD_CONCURRENCY
InnoDB有一种方法来控制并行执行的线程数 – 我们称为并发控制机制。大部分是由innodb_thread_concurrency值来控制的。如果设置为0,并发控制就关闭了,因此InnoDB会立即处理所有进来的请求(尽可能多的)。
在你有32CPU核心且只有4个请求时会没什么问题。不过想像下你只有4CPU核心和32个请求时 – 如果你让32个请求同时处理,你这个自找麻烦。因为这些32个请求只有4 CPU核心,显然地会比平常慢至少8倍(实际上是大于8倍),而然这些请求每个都有自己的外部和内部锁,这有很大可能堆积请求。
下面介绍如何更改这个变量,在mysql命令行提示符执行:
对于大多数工作负载和服务器,设置为8是一个好开端,然后你可以根据服务器达到了这个限制而资源使用率利用不足时逐渐增加。可以通过show engine innodb status\G来查看目前查询处理情况,查找类似如下行:
9.SKIP_NAME_RESOLVE
这一项不得不提及,因为仍然有很多人没有添加这一项。你应该添加skip_name_resolve来避免连接时DNS解析。
大多数情况下你更改这个会没有什么感觉,因为大多数情况下DNS服务器解析会非常快。不过当DNS服务器失败时,它会出现在你服务器上出现“unauthenticated connections” ,而就是为什么所有的请求都突然开始慢下来了。
所以不要等到这种事情发生才更改。现在添加这个变量并且避免基于主机名的授权。
10.INNODB_IO_CAPACITY, INNODB_IO_CAPACITY_MAX
* innodb_io_capacity:用来当刷新脏数据时,控制MySQL每秒执行的写IO量。
* innodb_io_capacity_max: 在压力下,控制当刷新脏数据时MySQL每秒执行的写IO量
首先,这与读取无关 – SELECT查询执行的操作。对于读操作,MySQL会尽最大可能处理并返回结果。至于写操作,MySQL在后台会循环刷新,在每一个循环会检查有多少数据需要刷新,并且不会用超过innodb_io_capacity指定的数来做刷新操作。这也包括更改缓冲区合并(在它们刷新到磁盘之前,更改缓冲区是辅助脏页存储的关键)。
第二,我需要解释一下什么叫“在压力下”,MySQL中称为”紧急情况”,是当MySQL在后台刷新时,它需要刷新一些数据为了让新的写操作进来。然后,MySQL会用到innodb_io_capacity_max。
那么,应该设置innodb_io_capacity和innodb_io_capacity_max为什么呢?
最好的方法是测量你的存储设置的随机写吞吐量,然后给innodb_io_capacity_max设置为你的设备能达到的最大IOPS。innodb_io_capacity就设置为它的50-75%,特别是你的系统主要是写操作时。
通常你可以预测你的系统的IOPS是多少。例如由8 15k硬盘组成的RAID10能做大约每秒1000随机写操作,所以你可以设置innodb_io_capacity=600和innodb_io_capacity_max=1000。许多廉价企业SSD可以做4,000-10,000 IOPS等。
这个值设置得不完美问题不大。但是,要注意默认的200和400会限制你的写吞吐量,因此你可能偶尔会捕捉到刷新进程。如果出现这种情况,可能是已经达到你硬盘的写IO吞吐量,或者这个值设置得太小限制了吞吐量。
11.INNODB_STATS_ON_METADATA
如果你跑的是MySQL 5.6或5.7,你不需要更改innodb_stats_on_metadata的默认值,因为它已经设置正确了。
不过在MySQL 5.5或5.1,强烈建议关闭这个变量 – 如果是开启,像命令show table status会立即查询INFORMATION_SCHEMA而不是等几秒再执行,这会使用到额外的IO操作。
从5.1.32版本开始,这个是动态变量,意味着你不需要重启MySQL服务器来关闭它。
12.INNODB_BUFFER_POOL_DUMP_AT_SHUTDOWN INNODB_BUFFER_POOL_LOAD_AT_STARTUP
innodb_buffer_pool_dump_at_shutdown和innodb_buffer_pool_load_at_startup这两个变量与性能无关,不过如果你偶尔重启mysql服务器(如生效配置),那么就有关。当两个都激活时,MySQL缓冲池的内容(更具体地说,是缓存页)在停止MySQL时存储到一个文件。当你下次启动MySQL时,它会在后台启动一个线程来加载缓冲池的内容以提高预热速度到3-5倍。
两件事:
第一,它实际上没有在关闭时复制缓冲池内容到文件,仅仅是复制表空间ID和页面ID – 足够的信息来定位硬盘上的页面了。然后它就能以大量的顺序读非常快速的加载那些页面,而不是需要成千上万的小随机读。
第二,启动时是在后台加载内容,因为MySQL不需要等到缓冲池内容加载完成再开始接受请求(所以看起来不会有什么影响)。
从MySQL 5.7.7开始,默认只有25%的缓冲池页面在mysql关闭时存储到文件,但是你可以控制这个值 – 使用innodb_buffer_pool_dump_pct,建议75-100。
这个特性从MySQL 5.6才开始支持。
13.INNODB_ADAPTIVE_HASH_INDEX_PARTS
如果你运行着一个大量SELECT查询的MySQL服务器(并且已经尽可能优化),那么自适应哈希索引将下你的下一个瓶颈。自适应哈希索引是InnoDB内部维护的动态索引,可以提高最常用的查询模式的性能。这个特性可以重启服务器关闭,不过默认下在mysql的所有版本开启。
这个技术非常复杂,在大多数情况下它会对大多数类型的查询直到加速的作用。不过,当你有太多的查询往数据库,在某一个点上它会花过多的时间等待AHI锁和闩锁。
如果你的是MySQL 5.7,没有这个问题 – innodb_adaptive_hash_index_parts默认设置为8,所以自适应哈希索引被切割为8个分区,因为不存在全局互斥。
不过在mysql 5.7前的版本,没有AHI分区数量的控制。换句话说,有一个全局互斥锁来保护AHI,可能导致你的select查询经常撞墙。
所以如果你运行的是5.1或5.6,并且有大量的select查询,最简单的方案就是切换成同一版本的Percona Server来激活AHI分区。
14.QUERY_CACHE_TYPE
如果人认为查询缓存效果很好,肯定应该使用它。好吧,有时候是有用的。不过这个只在你在低负载时有用,特别是在低负载下大多数是读取,小量写或者没有。
如果是那样的情况,设置query_cache_type=ON和query_cache_size=256M就好了。不过记住不能把256M设置更高的值了,否则会由于查询缓存失效时,导致引起严重的服务器停顿。
如果你的MySQL服务器高负载动作,建议设置query_cache_size=0和query_cache_type=OFF,并重启服务器生效。那样Mysql就会停止在所有的查询使用查询缓存互斥锁。
15.TABLE_OPEN_CACHE_INSTANCES
从MySQL 5.6.6开始,表缓存能分割到多个分区。
表缓存用来存放目前已打开表的列表,当每一个表打开或关闭互斥体就被锁定 – 即使这是一个隐式临时表。使用多个分区绝对减少了潜在的争用。
从MySQL 5.7.8开始,table_open_cache_instances=16是默认的配置。
欢迎做Java的工程师朋友们私信我资料免费获取免费的Java架构学习资料(里面有高可用、高并发、高性能及分布式、Jvm性能调优、Spring源码,MyBatis,Netty,Redis,Kafka,Mysql,Zookeeper,Tomcat,Docker,Dubbo,Nginx等多个知识点的架构资料)
其中覆盖了互联网的方方面面,期间碰到各种产品各种场景下的各种问题,很值得大家借鉴和学习,扩展自己的技术广度和知识面。
一、熟悉MySQL的运行环境
MySQL数据库是在Linux环境下运行的,建议先熟练Linux系统。选定好架构模式之后就可以开始进入程序开发和数据处理的环节。
二、有扎实的数据库理论知识
MySQL作为关系型数据库,在实际的应用中也要学会分析存储数据的关系型数据结构,关系操作集合等。只有对这些内容有一个明确的认识,在设计数据库字段、表与表的关系才能考虑周全,避免出现错误。
三、熟练的SQL语言运用
任何一种数据库的学习,包括MySQL,SQL语句都是位于核心部分的内容。需要注意的是SQL语言的使用要力求简明扼要,能用一个select搞定的问题并不需要写更多的union。所以在SQL语言的应用方面要注意高效。
我们在微信上24小时期待你的声音
解答本文疑问/技术咨询/运营咨询/技术建议/互联网交流