MySQL面试基础知识整理

MySQL复制原理

三个进程,两种文件。
binlog dump、IO thread、SQL thread
binlog 、relay log
以下图片截取自《高性能MySQL》

MySQL面试基础知识整理_第1张图片
MySQL面试基础知识整理_第2张图片
这里写图片描述

binlog日志格式的种类和优缺点

有三种格式:statement、mixed、row

1.statement:将修改数据的SQL记录在binlog中。
优点:
不需要记录每一行的变化,减少了binlog日志量,节约了IO,提高性能。
缺点:
由于记录的只是执行语句,为了这些语句能在slave上正确运行,因此还必须记录每条语句在执行的时候的一些相关信息,以保证所有语句能在slave得到和在master端执行时候相同的结果。
另外mysql 的复制,像一些特定函数功能,slave可与master上要保持一致会有很多相关问题(如sleep()函数, last_insert_id(),以及user-defined functions(udf)会出现问题)。

2.row:不记录sql语句上下文相关信息,仅保存哪条记录被修改。
优点:
binlog中可以不记录执行的sql语句的上下文相关的信息,仅需要记录那一条记录被修改成什么了。所以row level的日志内容会非常清楚的记录下每一行数据修改的细节。而且不会出现某些特定情况下的存储过程,或function,以及trigger的调用和触发无法被正确复制的问题
缺点:
所有的执行的语句当记录到日志中的时候,都将以每行记录的修改来记录,这样可能会产生大量的日志内容,比如一条update语句,修改多条记录,则binlog中每一条修改都会有记录,这样造成binlog日志量会很大,特别是当执行alter table之类的语句的时候,由于表结构修改,每条记录都发生改变,那么该表每一条记录都会记录到日志中。

3.Mixed:是以上两种level的混合使用,一般的语句修改使用statment格式保存binlog,如一些函数,statement无法完成主从复制的操作,则采用row格式保存binlog,MySQL会根据执行的每一条具体的sql语句来区分对待记录的日志形式,也就是在Statement和Row之间选择一种。

新版本的MySQL中对row level模式也被做了优化,并不是所有的修改都会以row level来记录,像遇到表结构变更的时候就会以statement模式来记录。至于update或者delete等修改数据的语句,还是会记录所有行的变更。

补充:
expire_logs_days= 7 //binlog过期清理时间
max_binlog_size=100m //binlog每个日志文件大小
sync_binlog

innodb事务与日志的实现

参考《MySQL技术内幕 Innodb存储引擎 》

Write-Ahead Logging ,WAL:预写日志方式
【1】Redo Log
在Innodb存储引擎中,事务日志是通过redo和innodb的存储引擎日志缓冲(Innodb log buffer)来实现的。
当开始一个事务的时候,会记录该事务的lsn(log sequence number)号;当事务执行时,会往InnoDB存储引擎的日志的日志缓存里面插入事务日志;当事务提交时,必须将存储引擎的日志缓冲写入磁盘(通过innodb_flush_log_at_trx_commit来控制),也就是写数据前,需要先写日志。
这种方式称为“预写日志方式”,innodb通过此方式来保证事务的完整性。也就意味着磁盘上存储的数据页和内存缓冲池上面的页是不同步的,是先写入redo log,然后写入data file,因此是一种异步的方式。通过 show engine innodb status\G 来观察之间的差距。

innodb_log_group_home_dir=/dbdata/iblogs
innodb_log_files_in_group=3
innodb_log_file_size=50M

【2】Undo
undo的记录正好与redo的相反,insert变成delete,update变成相反的update,redo放在redo file里面。而undo放在一个内部的一个特殊segment上面,存储与共享表空间内(ibdata1或者ibdata2中)。
undo不是物理恢复,是逻辑恢复,因为它是通过执行相反的dml语句来实现的。而且不会回收因为insert和upate而新增加的page页的。
undo页的回收是通过master thread线程来实现的。

在MySQL5.6中开始支持把undo log分离到独立的表空间,并放到单独的文件目录下;这给我们部署不同IO类型的文件位置带来便利,对于并发写入型负载,我们可以把undo文件部署到单独的高速存储设备上。

innodb_undo_tablespaces:用于设定创建的undo表空间的个数,在Install db时初始化后,就再也不能被改动了;默认值为0,表示不独立设置undo的tablespace,默认记录到ibdata中;否则,则在undo目录下创建这么多个undo文件,例如假定设置该值为16,那么就会创建命名为undo001~undo016的undo tablespace文件,每个文件的默认大小为10M。

innodb_undo_logs:用于表示回滚段的个数(早期版本的命名为innodb_rollback_segments),该变量可以动态调整,但是物理上的回滚段不会减少,只是会控制用到的回滚段的个数。

innodb_undo_directory:当开启独立undo表空间时,指定undo文件存放的目录。如果我们想转移undo文件的位置,只需要修改下该配置,并将undo文件拷贝过去就可以了。

当有长时间运行的事务时,可能导致purge操作来不及回收undo空间,进而导致undo空间急剧膨胀;理论上讲,如果做一次干净的shutdown,应该可以安全的将将这些undo文件删除并重新做一次初始化;也许未来的某个MySQL版本可能实现这个功能,这对于某些服务(比如按磁盘空间收费的云计算提供商)是非常有必要的功能。

innodb与myisam的索引实现方式

参考文章:http://blog.csdn.net/zuiaituantuan/article/details/5909334

1 MyISAM只把索引载入内存,数据缓存依赖于操作系统,InnoDB把索引和数据都载入内存缓冲 。
2 MyISAM数据库中的数据是按照插入的顺序保存,在每个索引节点中保存对应的数据行的地址,理论上说主键索引和其他索引是一样的,InnoDB数据库中的数据和主键节点保存在一起,所有其他索引节点中保存的是主键索引的值。
3 对于字符串索引,MyISAM默认采用增量保存,例如第一个索引值是’perform’,第二个索引的值是’performance’, 在索引文件中第二个索引被保存为’7,ance’。这样能够减小索引的尺寸。
4 MyISAM保存索引的状态信息在磁盘里,每次执行ANALYZE TABLE会更新这个信息。InnoDB则通过在启动的时候随机读取索引来估计索引的状态信息,所以Show Index的结果对于MyISAM是精准的,但对于InnoDB不是绝对精准。
5 索引长期运行之后会产生碎片,一种碎片是一行数据被保存在不同的数据段,另一种是连续的表空间或行在磁盘上被分散地保存。对于MyISAM两种索引碎片都会出现,对于InnoDB只会出现后一种因为InnoDB不会把短行保存到不同的数据段。要消除索引碎片一种方法是OPTIMIZE TABLE,另一种方法是把数据重新倒入。

针对MyISAM和InnoDB不同的索引结构,要注意以下几点:
1 在InnoDB表中插入数据一定要尽可能按照主键增加的顺序,AUTO_INCREMENT最好,这样插入的速度最快。
2 因为InnoDB索引节点中保存的是主键的值,所以主键的值越简单越好。
3 对于InnoDB表,在查询的时候如果只需要查找索引列,就不要加入其它列,这样速度最快。
索引逻辑结构:左边为innodb,右边为myisam。

Seconds_Behind_Master的确切含义

mysql在binlog中会记录event时间戳。binlog复制到slave节点并通过sql thread应用时,slave节点的时间和binlog中记录的event的时间戳之间的差就是Seconds_Behind_Master。
也就是说,如果slave节点系统时间比master节点系统时间晚一个小时,则每次有binlog event从master传输到slave并应用时,seconds_behind_master至少为3600。

一些MySQL高可用架构方面的言论

关于MySQL-HA,目前有多种解决方案,比如heartbeat、drbd、mmm、共享存储,但是它们各有优缺点。heartbeat、drbd配置较为复杂,需要自己写脚本才能实现MySQL自动切换,对于不会脚本语言的人来说,这无疑是一种脑裂问题;对于mmm,生产环境中很少有人用,且mmm 管理端需要单独运行一台服务器上,要是想实现高可用,就得对mmm管理端做HA,这样无疑又增加了硬件开支;对于共享存储,个人觉得MySQL数据还是放在本地较为安全,存储设备毕竟存在单点隐患。使用MySQL双master+keepalived是一种非常好的解决方案,在MySQL-HA环境中,MySQL互为主从关系,这样就保证了两台MySQL数据的一致性,然后用keepalived实现虚拟IP,通过keepalived自带的服务监控功能来实现MySQL故障时自动切换。

MySQL 高可用架构之MMM

简介

MMM(Master-Master replication manager for MySQL)是一套支持双主故障切换和双主日常管理的脚本程序。MMM使用Perl语言开发,主要用来监控和管理MySQL Master-Master(双主)复制,虽然叫做双主复制,但是业务上同一时刻只允许对一个主进行写入,另一台备选主上提供部分读服务,以加速在主主切换时刻备选主的预热,可以说MMM这套脚本程序一方面实现了故障切换的功能,另一方面其内部附加的工具脚本也可以实现多个slave的read负载均衡。

MMM提供了自动和手动两种方式移除一组服务器中复制延迟较高的服务器的虚拟ip,同时它还可以备份数据,实现两节点之间的数据同步等。由于MMM无法完全的保证数据一致性,所以MMM适用于对数据的一致性要求不是很高,但是又想最大程度的保证业务可用性的场景。对于那些对数据的一致性要求很高的业务,非常不建议采用MMM这种高可用架构。

总结:
MMM不适用于对数据一致性要求很高的环境。但是高可用完全做到了。

详细搭建及配置等请移步:(非常好的文章)
http://www.tuicool.com/articles/qQVN3yA

MySQL高可用架构之MM+Keepalived

具体环境搭建步骤请移步:
lvs+keepalived+mha+mysql高可用架构配置说明
http://www.chocolee.cn/archives/276

KeepAlived + mysqlMM高可用 安装配置
http://blog.chinaunix.net/uid-25135004-id-3807798.html

批量MySQL数据库管理经验

实际线上的mysql数据库数量有多少?分多少个节点组?
这些节点组上面的slow log是如何组合在一起来统计分析的?
现在手上有600台数据库,新来的机器,Mysql都安装好了,那么你如何在最快的时间里面把这600台mysql数据库的mysqld服务启动起来?这个重点在于最快的时间。

SQL优化的思路及基本原则

SQL优化的思路:
1.优化更需要优化的sql;
2.定位优化对象的性能瓶颈:优化前需了解查询的瓶颈是IO还是CPU,可通过PROFILING很容易定位查询的瓶颈。
3.明确优化目标;
4.从Explain入手;
5.多使用profile;

SQL优化的基本原则:
1.永远用小结果集驱动大结果集;
From子句中sql解析顺序为从右向左,执行时会以最左边的表为基础表循环与右边表数据做笛卡尔积,所以以小结果集驱动能减少循环次数,从而减少对被驱动结果集的访问,从而减少被驱动表的锁定。
2.尽可能在索引中完成排序;
排序算法有两种:a.查出排序字段和行指针,排序,再通过行指针获得行数据所需列,返回结果集;b.取出所有排序列数据,在排序缓冲区中排完序直接返回结果集。
索引排序是利用索引的有序性对数据排序的。
3.只取出子集需要的colums
4.仅仅使用最有效的过滤条件;
5.尽可能避免复杂的Join和子查询;

索引的好处:
(1).提高数据检索效率,降低数据库的IO成本。
(2).降低数据排序成本:要求排序字段和索引键字段一致。
(3).降低数据分组成本:因为分组之前会先排序,同意如果分组字段与索引字段一致,会降低分组消耗的成本。
索引的弊端:
(1).索引是独立于基础数据的数据库对象,因此它会占用存储空间。
(2).数据新增、更新会导致索引的同步更新,所以会增加数据新增、更新所消耗的成本。
判断是否需要创建索引:
(1).较为频繁的作为查询条件的字段需要创建索引;
(2). 唯一性太差的字段不适合单独创建索引,即使频繁作为查询条件;
(3).更新非常频繁的字段不适合创建索引;
(4).不会出现在where子句中的字段不要创建索引;

索引语法:
(1).唯一索引
ALTER TABLE tableName ADD UNIQUE indexName (column);
CREATE UNIQUE INDEX indexName ON tableName (column);
(2).普通索引
ALTER TABLE tableName ADD INDEX indexName(column);
CREATE INDEX indexName ON tableName(column);
(3).主键索引
ALTER TABLE tableName ADD PRIMARY KEY (column);
(4).全文索引
ALTER TABLE tableName ADD FULLTEXT (column);
(5).组合索引
ALTER TABLE tableName ADD INDEX indexName(col1,col2,…);

MySQL explain的各种参数

参考自己的博客:
mysql explain 输出详解
http://blog.csdn.net/lijingkuan/article/details/50462372

对mysql explain讲的比较清楚的(转)
http://blog.csdn.net/lijingkuan/article/details/50432680

MySQL explain中的file sort含义及出现场景

在使用order by关键字的时候,如果待排序的内容不能由所使用的索引直接完成排序的话,那么mysql有可能就要进行文件排序。

【这个 filesort 并不是说通过磁盘文件进行排序,而只是告诉我们进行了一个排序操作而已】。

当然,using filesort不一定引起mysql的性能问题。但是如果查询次数非常多,那么每次在mysql中进行排序,还是会有影响的。
此时,可以进行的优化:
1、修改逻辑,不在mysql中使用order by而是在应用中自己进行排序。
2、使用mysql索引,将待排序的内容放到索引中,直接利用索引的排序。

详情参考:
http://blog.csdn.net/imzoer/article/details/8485680

MySQL explain中的using temporary含义及出现场景

有待整理

MySql中explain之后,type字段和Extra字段中的index区别

一个查询语句经过explain之后,type字段可能会出现index,Extra中可能会出现using index。

那么二者有什么区别呢?他们是迥然不同的。

type中的index,仅仅是说,查询类型index,表示本次查询仅仅扫描索引树,没有其他读取操作。

Extra中的using index,意思是说,查询使用到了“覆盖索引”。

详情参考:
http://blog.csdn.net/imzoer/article/details/8533929

MySQL profile

参考:
mysql使用profile分析语句性能消耗
http://blog.itpub.net/29371470/viewspace-1355948/

关于数据类型

以下图片截取自《高性能MySQL》
整数类型
MySQL面试基础知识整理_第3张图片
这里写图片描述
字符类型
MySQL面试基础知识整理_第4张图片
BLOB&TEXT

这里写图片描述

MySQL部分配置参数介绍

非缓存参数变量

back_log
back_log值指出在MySQL暂时停止回答新请求之前的短时间内多少个请求可以被存在堆栈中。也就是说,如果MySql的连接数据达到max_connections时,新来的请求将会被存在堆栈中,以等待某一连接释放资源,该堆栈的数量即back_log,如果等待连接的数量超过back_log,将不被授予连接资源。将会报:
unauthenticated user | xxx.xxx.xxx.xxx | NULL | Connect | NULL | login | NULL
的等待连接进程时。(这个现象在通过DNS解析连接的时候也出现过。)
back_log值不能超过TCP/IP连接的侦听队列的大小。若超过则无效,查看当前系统的TCP/IP连接的侦听队列的大小命令:

cat /proc/sys/net/ipv4/tcp_max_syn_backlog

目前系统为1024。
对于Linux系统推荐设置为小于512的整数。
修改系统内核参数http://www.51testing.com/html/64/n-810764.html
查看mysql 当前系统默认back_log值,命令:

show variables like 'back_log'; 

wait_timeout
我对wait-timeout这个参数的理解:
MySQL客户端的数据库连接闲置最大时间值。
说得比较通俗一点,就是当你的MySQL连接闲置超过一定时间后将会被强行关闭。
MySQL默认的wait-timeout 值为8个小时,可以通过命令show variables like 'wait_timeout'查看结果值。
设置这个值是非常有意义的,比如你的网站有大量的MySQL链接请求(每个MySQL连接都是要内存资源开销的 ),由于你的程序的原因有大量的连接请求空闲啥事也不干,白白占用内存资源,或者导致MySQL超过最大连接数从来无法新建连接导致“Too many connections”的错误。在设置之前你可以查看一下你的MYSQL的状态(可用show processlist),如果经常发现MYSQL中有大量的Sleep进程,则需要 修改wait-timeout值了。
扩展:interactive_timeout,wait_timeout

max_connections
max_connections是指MySql的最大连接数,如果服务器的并发连接请求量比较大,建议调高此值,以增加并行连接数量,当然这建立在机器能支撑的情况下,因为如果连接数越多,介于MySql会为每个连接提供连接缓冲区,就会开销越多的内存,所以要适当调整该值,不能盲目提高设值。可以过’conn%’通配符查看当前状态的连接数量,以定夺该值的大小。
MySQL服务器允许的最大连接数16384;
查看系统当前最大连接数:

show variables like 'max_connections';

max_user_connections
max_user_connections是指每个数据库用户的最大连接。
针对某一个账号的所有客户端并行连接到MYSQL服务的最大并行连接数。
简单说是指同一个账号能够同时连接到mysql服务的最大连接数。
设置为0表示不限制。目前默认值为:0不受限制。
这儿顺便介绍下Max_used_connections:它是指从这次mysql服务启动到现在,同一时刻并行连接数的最大值。它不是指当前的连接情况,而是一个比较值。如果在过去某一个时刻,MYSQL服务同时有1000个请求连接过来,而之后再也没有出现这么大的并发请求时,则Max_used_connections=1000。请注意与show variables 里的max_user_connections的区别。默认为0表示无限大。
查看max_user_connections值

show variables like 'max_user_connections';

thread_concurrency
thread_concurrency的值的正确与否, 对mysql的性能影响很大。
在多个cpu(或多核)的情况下,错误设置了thread_concurrency的值, 会导致mysql不能充分利用多cpu(或多核), 出现同一时刻只能一个cpu(或核)在工作的情况。
thread_concurrency应设为CPU核数的2倍。比如有一个双核的CPU, 那thread_concurrency 的应该为4; 2个双核的cpu, thread_concurrency的值应为8.
比如:根据上面介绍我们目前系统的配置,可知道为4个CPU,每个CPU为8核,按照上面的计算规则,这儿应为:4*8*2=64
查看系统当前thread_concurrency默认配置命令:

show variables like 'thread_concurrency';

skip-name-resolve
禁止MySQL对外部连接进行DNS解析,使用这一选项可以消除MySQL进行DNS解析的时间。
但需要注意,如果开启该选项,则所有远程主机连接授权都要使用IP地址方式,否则MySQL将无法正常处理连接请求!(主机名连接方式就不能用了。)

skip-networking
建议被注释掉,不要开启。
开启该选项可以彻底关闭MySQL的TCP/IP连接方式,如果WEB服务器是以远程连接的方式访问MySQL数据库服务器则不要开启该选项!否则将无法正常连接!

缓存参数优化

数据库属于IO密集型的应用程序,其主职责就是数据的管理及存储工作。而我们知道,从内存中读取一个数据库的时间是微秒级别,而从一块普通硬盘上读取一个 IO是在毫秒级别,二者相差3个数量级。所以,要优化数据库,首先第一步需要优化的就是IO,尽可能将磁盘IO转化为内存IO。本文先从MySQL数据库 IO相关参数(缓存参数)的角度来看看可以通过哪些参数进行IO优化。

全局缓存

启动MySQL时就要分配并且总是存在的全局缓存。目前有:key_buffer_size(默认值:402653184,即384M)
innodb_buffer_pool_size(默认值:134217728即:128M)
innodb_additional_mem_pool_size(默认值:8388608即:8M)
innodb_log_buffer_size(默认值:8388608即:8M)
query_cache_size(默认值:33554432即:32M)等五个。
总共:560M。
这些变量值都可以通过命令如:show variables like '变量名';查看到。

key_buffer_size
key_buffer_size是用于索引块的缓冲区大小,增加它可得到更好处理的索引(对所有读和多重写),对MyISAM(MySQL表存储的一种类型,可以百度等查看详情)表性能影响最大的一个参数。
如果你使它太大,系统将开始换页并且真的变慢了。严格说是它决定了数据库索引处理的速度,尤其是索引读的速度。对于内存在4GB左右的服务器该参数可设置为256M或384M.
怎么才能知道key_buffer_size的设置是否合理呢,一般可以检查状态值Key_read_requests和Key_reads ,比例key_reads / key_read_requests应该尽可能的低,比如1:100,1:1000 ,1:10000。
其值可以用以下命令查得:show status like 'key_read%';
比如查看系统当前key_read和key_read_request值为:
+——————-+——-+
| Variable_name | Value |
+——————-+——-+
| Key_read_requests | 28535 |
| Key_reads | 269 |
+——————-+——-+
可知道有28535个请求,有269个请求在内存中没有找到直接从硬盘读取索引。
未命中缓存的概率为:0.94%=269/28535*100%。一般未命中概率在0.1之下比较好。目前已远远大于0.1,证明效果不好。若命中率在0.01以下,则建议适当的修改key_buffer_size值。

innodb_buffer_pool_size
主要针对InnoDB表性能影响最大的一个参数。功能与Key_buffer_size一样。InnoDB占用的内存,除innodb_buffer_pool_size用于存储页面缓存数据外,另外正常情况下还有大约8%的开销,主要用在每个缓存页帧的描述、adaptive hash等数据结构,如果不是安全关闭,启动时还要恢复的话,还要另开大约12%的内存用于恢复,两者相加就有差不多21%的开销。假设:12G的innodb_buffer_pool_size,最多的时候InnoDB就可能占用到14.5G的内存。若系统只有16G,而且只运行MySQL,且MySQL只用InnoDB,那么为MySQL开12G,是最大限度地利用内存了。
另外InnoDB和 MyISAM 存储引擎不同, MyISAM 的 key_buffer_size 只能缓存索引键,而 innodb_buffer_pool_size 却可以缓存数据块和索引键。适当的增加这个参数的大小,可以有效的减少 InnoDB 类型的表的磁盘 I/O 。
当我们操作一个 InnoDB 表的时候,返回的所有数据或者取数据过程中用到的任何一个索引块,都会在这个内存区域中走一遭。
可以通过

(Innodb_buffer_pool_read_requests – Innodb_buffer_pool_reads) / Innodb_buffer_pool_read_requests * 100% 

计算缓存命中率,并根据命中率来调整 innodb_buffer_pool_size 参数大小进行优化。
值可以用以下命令查得:show status like 'Innodb_buffer_pool_read%';
比如查看当前系统中系统中
| Innodb_buffer_pool_read_requests | 1283826 |
| Innodb_buffer_pool_reads | 519 |
+—————————————+———+
其命中率99.959%=(1283826-519)/1283826*100% 命中率越高越好。

innodb_additional_mem_pool_size
设置了InnoDB存储引擎用来存放数据字典信息以及一些内部数据结构的内存空间大小,所以当我们一个MySQL Instance中的数据库对象非常多的时候,是需要适当调整该参数的大小以确保所有数据都能存放在内存中提高访问效率的。
这个参数大小是否足够还是比较容易知道的,因为当过小的时候,MySQL会记录Warning信息到数据库的error log中,这时候你就知道该调整这个参数大小了。
查看当前系统mysql的error日志 cat /var/lib/mysql/机器名.error 发现有很多waring警告。所以要调大为20M。
根据MySQL手册,对于2G内存的机器,推荐值是20M。32G内存的 100M。

innodb_log_buffer_size
这是InnoDB存储引擎的事务日志所使用的缓冲区。类似于Binlog Buffer,InnoDB在写事务日志的时候,为了提高性能,也是先将信息写入Innodb Log Buffer中,当满足innodb_flush_log_trx_commit参数所设置的相应条件(或者日志缓冲区写满)之后,才会将日志写到文件 (或者同步到磁盘)中。可以通过innodb_log_buffer_size 参数设置其可以使用的最大内存空间。
InnoDB 将日志写入日志磁盘文件前的缓冲大小。理想值为 1M 至 8M。大的日志缓冲允许事务运行时不需要将日志保存入磁盘而只到事务被提交(commit)。 因此,如果有大的事务处理,设置大的日志缓冲可以减少磁盘I/O。 在 my.cnf中以数字格式设置。
默认是8MB,频繁的系统可适当增大至4MB~8MB。当然如上面介绍所说,这个参数实际上还和另外的flush参数相关。一般来说不建议超过32MB
注:innodb_flush_log_trx_commit参数对InnoDB Log的写入性能有非常关键的影响,默认值为1。该参数可以设置为0,1,2,解释如下:
0:log buffer中的数据将以每秒一次的频率写入到log file中,且同时会进行文件系统到磁盘的同步操作,但是每个事务的commit并不会触发任何log buffer 到log file的刷新或者文件系统到磁盘的刷新操作;
1:在每次事务提交的时候将log buffer 中的数据都会写入到log file,同时也会触发文件系统到磁盘的同步;
2:事务提交会触发log buffer到log file的刷新,但并不会触发磁盘文件系统到磁盘的同步。此外,每秒会有一次文件系统到磁盘同步操作。
实际测试发现,该值对插入数据的速度影响非常大,设置为2时插入10000条记录只需要2秒,设置为0时只需要1秒,而设置为1时则需要229秒。因此,MySQL手册也建议尽量将插入操作合并成一个事务,这样可以大幅提高速度。根据MySQL手册,在存在丢失最近部分事务的危险的前提下,可以把该值设为0。

query_cache_size
主要用来缓存MySQL中的ResultSet,也就是一条SQL语句执行的结果集,所以仅仅只能针对select语句。当我们打开了 Query Cache功能,MySQL在接受到一条select语句的请求后,如果该语句满足Query Cache的要求(未显式说明不允许使用Query Cache,或者已经显式申明需要使用Query Cache),MySQL会直接根据预先设定好的HASH算法将接受到的select语句以字符串方式进行hash,然后到Query Cache中直接查找是否已经缓存。也就是说,如果已经在缓存中,该select请求就会直接将数据返回,从而省略了后面所有的步骤(如SQL语句的解析,优化器优化以及向存储引擎请求数据等),极大的提高性能。根据MySQL用户手册,使用查询缓冲最多可以达到238%的效率。
当然,Query Cache也有一个致命的缺陷,那就是当某个表的数据有任何任何变化,都会导致所有引用了该表的select语句在Query Cache中的缓存数据失效。所以,当我们的数据变化非常频繁的情况下,使用Query Cache可能会得不偿失。
Query Cache的使用需要多个参数配合,其中最为关键的是query_cache_size和query_cache_type,前者设置用于缓存 ResultSet的内存大小,后者设置在何场景下使用Query Cache。在以往的经验来看,如果不是用来缓存基本不变的数据的MySQL数据库,query_cache_size一般256MB是一个比较合适的大小。当然,这可以通过计算Query Cache的命中率(Qcache_hits/(Qcache_hits+Qcache_inserts)*100))来进行调整。 query_cache_type可以设置为0(OFF),1(ON)或者2(DEMOND),分别表示完全不使用query cache,除显式要求不使用query cache(使用sql_no_cache)之外的所有的select都使用query cache,只有显示要求才使用query cache(使用sql_cache)。如果Qcache_lowmem_prunes(该参数记录有多少条查询因为内存不足而被移除出查询缓存。通过这个值,用户可以适当的调整缓存大小。 )的值非常大,则表明经常出现缓冲. 如果Qcache_hits的值也非常大,则表明查询缓冲使用非常频繁,此时需要增加缓冲大小;
根据命中率(Qcache_hits/(Qcache_hits+Qcache_inserts)*100))进行调整,一般不建议太大,256MB可能已经差不多了,大型的配置型静态数据可适当调大.
可以通过命令:show status like ‘Qcache_%’;查看目前系统Query cache使用大小
| Qcache_hits | 1892463 |
| Qcache_inserts | 35627
命中率98.17%=1892463/(1892463 +35627 )*100

局部缓存

除了全局缓冲,MySql还会为每个连接发放连接缓冲。每个连接到MySQL服务器的线程都需要有自己的缓冲。大概需要立刻分配256K,甚至在线程空闲时,它们使用默认的线程堆栈,网络缓存等。
事务开始之后,则需要增加更多的空间。
运行较小的查询可能仅给指定的线程增加少量的内存消耗,然而如果对数据表做复杂的操作例如扫描、排序或者需要临时表,则需分配大约read_buffer_size,sort_buffer_size,read_rnd_buffer_size,tmp_table_size 大小的内存空间。
不过它们只是在需要的时候才分配,并且在那些操作做完之后就释放了。有的是立刻分配成单独的组块。tmp_table_size 可能高达MySQL所能分配给这个操作的最大内存空间了。
注意,这里需要考虑的不只有一点——可能会分配多个同一种类型的缓存,例如用来处理子查询。
一些特殊的查询的内存使用量可能更大——如果在MyISAM表上做成批的插入时需要分配 bulk_insert_buffer_size 大小的内存;执行 ALTER TABLE, OPTIMIZE TABLE, REPAIR TABLE 命令时需要分配 myisam_sort_buffer_size 大小的内存。

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

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

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

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

record_buffer
record_buffer每个进行一个顺序扫描的线程为其扫描的每张表分配这个大小的一个缓冲区。如果你做很多顺序扫描,你可能想要增加该值。默认数值是131072(128K)。

其他缓存

TABLE_CACHE
(5.1.3及以后版本又名TABLE_OPEN_CACHE)
存放当前已经打开的表句柄。
table_cache指定表高速缓存的大小。(所有线程的总和)
每当MySQL访问一个表时,如果在表缓冲区中还有空间,该表就被打开并放入其中,这样可以更快地访问表内容。
通过检查峰值时间的状态值Open_tables和Opened_tables,可以决定是否需要增加table_cache的值。如果你发现open_tables等于table_cache,并且opened_tables在不断增长,那么你就需要增加table_cache的值了(上述状态值可以使用SHOW STATUS LIKE ‘Open%tables’获得)。
注意,不能盲目地把table_cache设置成很大的值。如果设置得太高,可能会造成文件描述符不足,从而造成性能不稳定或者连接失败。

SHOW STATUS LIKE 'Open%tables'; +---------------+-------+
| Variable_name | Value | +---------------+-------+
| Open_tables | 356 | | Opened_tables | 0     |
+---------------+-------+
2 rows in set (0.00 sec)

open_tables表示当前打开的表缓存数,如果执行flush tables操作,则此系统会关闭一些当前没有使用的表缓存而使得此状态值减小;
opend_tables表示曾经打开的表缓存数,会一直进行累加,如果执行flush tables操作,值不会减小。
在mysql默认安装情况下,table_cache的值在2G内存以下的机器中的值默认时256到512,如果机器有4G内存,则默认这个值 是2048,但这决意味着机器内存越大,这个值应该越大,因为table_cache加大后,使得mysql对SQL响应的速度更快了,不可避免的会产生 更多的死锁(dead lock),这样反而使得数据库整个一套操作慢了下来,严重影响性能。所以平时维护中还是要根据库的实际情况去作出判断,找到最适合你维护的库的 table_cache值。
由于MySQL是多线程的机制,为了提高性能,每个线程都是独自打开自己需要的表的文件描述符,而不是通过共享已经打开的。
针对不同存储引擎处理的方法当然也不一样:
在myisam表引擎中,数据文件的描述符 (descriptor)是不共享的,但是索引文件的描述符却是所有线程共享的。
Innodb中和使用表空间类型有关,假如是共享表空间那么实际就一个数据文件,当然占用的数据文件描述符就会比独立表空间少。
mysql手册上给的建议大小 是:table_cache=max_connections*n
n表示查询语句中最大表数, 还需要为临时表和文件保留一些额外的文件描述符。
这个数据遭到很多质疑,table_cache够用就好,检查 Opened_tables值,如果这个值很大,或增长很快那么你就得考虑加大table_cache了.
table_cache:所有线程打开的表的数目。增大该值可以增加mysqld需要的文件描述符的数量。默认值是64。

thread_cache_size
默认的thread_cache_size=8,但是看到好多配置的样例里的值一般是32,64,甚至是128,感觉这个参数对优化应该有帮助,于是查了下:
根据调查发现以上服务器线程缓存thread_cache_size没有进行设置,或者设置过小,这个值表示可以重新利用保存在缓存中线程的数量,当断开连接时如果缓存中还有空间,那么客户端的线程将被放到缓存中。如果线程重新被请求,那么请求将从缓存中读取。如果缓存中是空的或者是新的请求,那么这个线程将被重新创建。如果有很多新的线程,增加这个值可以改善系统性能。
通过比较 Connections 和 Threads_created 状态的变量,可以看到这个变量的作用。(–>表示要调整的值) 根据物理内存设置规则如下:
1G —> 8
2G —> 16
3G —> 32 >3G —> 64

mysql> show status like 'thread%';
| Variable_name | Value |
| Threads_cached | 0 | <—当前被缓存的空闲线程的数量
| Threads_connected | 1 | <—正在使用(处于连接状态)的线程
| Threads_created | 1498 | <—服务启动以来,创建了多少个线程
| Threads_running | 1 | <—正在忙的线程(正在查询数据,传输数据等等操作)

查看开机起来数据库被连接了多少次?

mysql> show status like '%connection%';
| Variable_name | Value |
| Connections | 1504 | –>服务启动以来,历史连接数
| Max_used_connections | 2 |

通过连接线程池的命中率来判断设置值是否合适?命中率超过90%以上,设定合理。
(Connections - Threads_created) / Connections * 100 %

Table definition cache
存放表的定义信息。是frm文件在内存中的映射。MySQL需要打开frm文件,并将其内容初始化为Table Share 对象。这里存放与存储引擎无关的,独立的表定义相关信息。
与table_cached是两个概念完全不同的东西。为什么MySQL会出现这两个概念是因为:MySQL支持不同的存储引擎,每种存储引擎,数据存储的格式都是不一样的,因此需要指定一个存储引擎相关的handler。这就有了table cache的作用。另外表的定义也需要存放内存中,而表的定义frm文件每个存储引擎是通用的,需要另外独立开来,这就有了table definition cache。

数据库隔离级别

SQL标准定义的四个隔离级别为:
read uncommited
read committed
repeatable read
serializable

Read Uncommitted(读取未提交内容)
在该隔离级别,所有事务都可以看到其他未提交事务的执行结果。本隔离级别很少用于实际应用,因为它的性能也不比其他级别好多少。读取未提交的数据,也被称之为脏读(Dirty Read)。

Read Committed(读取提交内容)
这是大多数数据库系统的默认隔离级别(但不是MySQL默认的)。它满足了隔离的简单定义:一个事务只能看见已经提交事务所做的改变。这种隔离级别也支持所谓的不可重复读(Nonrepeatable Read),因为同一事务的其他实例在该实例处理其间可能会有新的commit,所以同一select可能返回不同结果。

Repeatable Read(可重读)
这是MySQL的默认事务隔离级别,它确保同一事务的多个实例在并发读取数据时,会看到同样的数据行。不过理论上,这会导致另一个棘手的问题:幻读(Phantom Read)。简单的说,幻读指当用户读取某一范围的数据行时,另一个事务又在该范围内插入了新行,当用户再读取该范围的数据行时,会发现有新的“幻影” 行。InnoDB和Falcon存储引擎通过多版本并发控制(MVCC,Multiversion Concurrency Control 间隙锁)机制解决了该问题。注:其实多版本只是解决不可重复读问题,而加上间隙锁(也就是它这里所谓的并发控制)才解决了幻读问题。

Serializable(可串行化)
这是最高的隔离级别,它通过强制事务排序,使之不可能相互冲突,从而解决幻读问题。简言之,它是在每个读的数据行上加上共享锁。在这个级别,可能导致大量的超时现象和锁竞争。

对于不同的事务,采用不同的隔离级别分别有不同的结果。不同的隔离级别有不同的现象。主要有下面3种现在:
1、脏读(dirty read):一个事务可以读取另一个尚未提交事务的修改数据。
2、非重复读(nonrepeatable read):在同一个事务中,同一个查询在T1时间读取某一行,在T2时间重新读取这一行时候,这一行的数据已经发生修改,可能被更新了(update),也可能被删除了(delete)。
3、幻像读(phantom read):在同一事务中,同一查询多次进行时候,由于其他插入操作(insert)的事务提交,导致每次返回不同的结果集。

不同的隔离级别有不同的现象,并有不同的锁定/并发机制,隔离级别越高,数据库的并发性就越差,4种事务隔离级别分别表现的现象如下表:

mysql锁模式

共享锁
排它锁
意向锁(表级锁,在加共享锁或排它锁之前,要先获得意向锁。)

可以参考:

innodb record-level锁

record lock
gap lock
next-key lock

具体加锁规则参考:
http://blog.csdn.net/lijingkuan/article/details/50754236

MyISAM和Innodb引擎的区别

mysqldump以及xtranbackup的实现原理

mysqldump是最简单的逻辑备份方式。在备份myisam表的时候,如果要得到一致的数据,就需要锁表,简单而粗暴。而在备份innodb表 的时候,加上–master-data=1 –single-transaction 选项,在事务开始时刻,记录下binlog pos点,然后利用mvcc来获取一致的数据,由于是一个长事务,在写入和更新量很大的数据库上,将产生非常多的undo,显著影响性能,所以要慎用

 优点:简单,可针对单表备份,在全量导出表结构的时候尤其有用。

  缺点:简单粗暴,单线程,备份慢而且恢复慢,跨IDC有可能遇到时区问题

xtrabackup它实际上是物理备份+逻辑备份的组合。在备份 innodb表的时候,它拷贝ibd文件,并一刻不停的监视redo log的变化,append到自己的事务日志文件。在拷贝ibd文件过程中,ibd文件本身可能被写”花”,这都不是问题,因为在拷贝完成后的第一个 prepare阶段,Xtrabackup采用类似于innodb崩溃恢复的方法,把数据文件恢复到与日志文件一致的状态,并把未提交的事务回滚。如果同 时需要备份myisam表以及innodb表结构等文件,那么就需要用flush tables with lock来获得全局锁,开始拷贝这些不再变化的文件,同时获得binlog位置,拷贝结束后释放锁,也停止对redo log的监视。

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