《Mysql技术内幕》札记(上)

第一章   MYSQL体系结构和存储引擎

一、数据库的概念

数据库:数据库文件类型的集合,以frm与ibd结尾等。

数据库实例:数据库后台的进程/线程 以及共享内存组成,实例操作数据库文件
数据库与实例一一对应,一个实例对应一个数据库
Mysql是单进程多线程,这就意味着一个实例一个进程

                           MYSQL架构

   SQL接口组件   查询分析器组件    优化器组件    缓存
                      插件式存储引擎(基于表)
                          物理文件

二、不同引擎

Innodb存储引擎

事务应用的特点:行锁,外,非锁定读 
高性能功能:1.写入方面:插入缓冲,二次写 2.查询方面:自适应哈希索引,预读 
Myisam引擎
Myisam由myd和myi文件组成。myd数据文件和myi索引文件

三、连接mysql 

连接进程是mysql连接进程和数据库实例进行通信,本质上是进程的通信。 

通信方式一般有:TCP/IP,unix套接字等 
1.在网络中MYSQL连接是通过用TCP/IP套接字方式 
##TCP/IP套接字方式时,实例在连接时会检查权限表user,用来判断连接是否被允许。 
2. Unix套接字连接,适用于客户端与服务器在同一台服务器。用--socket=**** 来连接。可以通过ps -ef|grep 'mysql'查询套接字以及配置文件


第一章   innodb存储引擎

一、Innodb后台线程

后台线程有7个 
4个io thread 1个master线程 1个锁线程 1个错误监控

io四个线程:

Insert buffer thread
Log thread
Write thread
Read thread

show engine innodb status;
--------
FILE I/O
--------
I/O thread 0 state: waiting for i/o request (insertbuffer thread)
I/O thread 1 state: waiting for i/o request (log thread)
I/O thread 2 state: waiting for i/o request (read thread)
I/O thread 3 state: waiting for i/o request (writethread)

二、内存


内存由以下组成:缓冲池,重做日志缓冲池,额外内存池。 
缓冲池大小查看:

show variables like '%buffer%';

+------------------------------+------------+

| Variable_name          | Value      |

+------------------------------+------------+

| innodb_buffer_pool_size    | 6442450944 |

| innodb_log_buffer_size     | 33554432   |

+------------------------------+------------+

缓冲池

缓冲池的数据页:数据页,索引页 ,undo页,插入缓冲,自适应哈希索引,锁信息和数据字典 
数据按页读到缓冲池,将最近最多使用的数据页留在缓冲池,只要数据文件需要修改就更新缓存池的页,然后缓冲池的脏页会按照一定的频率刷到文件

缓存池具体使用情况:

----------------------
BUFFER POOL AND MEMORY
----------------------
Total memory allocated 6593445888; in additional poolallocated 0
Dictionary memory allocated 9473932
Buffer pool size  393215 一共**缓冲帧(每个帧页为16k)
Free buffers      0     空闲缓冲帧
Database pages    381113  已使用的缓冲帧
Old database pages 140664    最近没有被访问的页(会被替换出去)
Modified db pages 0   表示脏页

Old database pages 解释:http://www.orczhou.com/index.php/2010/05/innodb-plugin-make-buffer-cache-scan-resistant/

当数据页被替换到内存时,为了避免数据污染(热数据被全部替换)将在不热的数据队列进行读取,过一定的时间还有读取才会替换最热的缓存。

##show engine innodb status 统计的数据不是实时
=====================================
151106 14:20:53 INNODB MONITOR OUTPUT
=====================================
Per second averages calculated from the last 17 seconds 
(此数据库服务器统计的数据是前17秒的数据)

日志缓冲数据一般情况下每一秒将刷新到磁盘,所以日志缓冲区大小不需要太大
额外内存池:数据结构分配内存时使用 

三、线程

master thread,线程优先级最高,由主循环,后台循环,刷新循环,暂停循环构成。
主循环分两个:每秒操作以及每10秒操作 
每秒操作操作:
1.日志缓冲刷新到磁盘(总是)即使没有提交,很好解释commit为什么很快
2.合并插入缓冲(可能)io小于5次
3.至多刷新100个innodb的缓冲池的脏数据到磁盘(可能)脏数据数据到达脏页比例(innodb_max_dirty_pages_pct,可以在线修改)
4.切换到后台循环 当前没有活动
每10秒操作: 
1.合并至多5个插入缓存 (总是)
2.刷新100个或者10个脏页到磁盘(总是)如果脏页超过70%,刷新100个脏页,不到70%,刷新10%的脏页
3.删除undo无用页(总是)  原已经删除但是行版本问题还存在的页 
4.产生一个检查点 (总是) 将最老的日志序列写入磁盘
5.没有用户活动时切到background :loop删除无用undo页,合并20个插入缓存,刷新100个页

6.跳到flush loop(可能,容易切换suspend_loop,将Master thread挂起)
show engine innodb status;

show engine innodbstatus;
-----------------
BACKGROUND THREAD
-----------------
srv_master_threadloops: 13146906 1_second, 13146039 sleeps, 1314246 10_second, 17451 background,17451 flush
srv_master_threadlog flush and writes: 13182400


主循环一秒的操作13146906,每秒休眠次数13146039,每10秒的操作1314246,后台循环17451,刷新循环17451

一秒的操作与每秒休眠次数越相等说明服务器压力越小
数据量大时大量数据不在磁盘宕机后恢复时间长 100页写入磁盘还行吗?
innodb_adaptive_flushing适应性的刷新通过参考日志的写入速度,调整每次刷新到磁盘的页数。这时没到innodb_max_dirty_pages_pct比例也会有脏数据被刷新到磁盘

四、关键特性

插入缓冲:插入聚集索引一般是顺序的,不需要随机读,非聚集索引需要按照索引建查找,此时离散读降低性能,所以引入插入缓冲

插入缓冲使用条件:
1.索引是辅助索引
2.索引不唯一 
辅助索引唯一,就避免了离散读,插入缓冲就没了意义。通常多个插入合并到一个操作,提高了插入和修改操作。

show engine innodbstatus;
-------------------------------------
INSERT BUFFER ANDADAPTIVE HASH INDEX
-------------------------------------
Ibuf: size 1, freelist len 41069, seg size 41071, 172271 merges
merged operations:
 insert 133199, delete mark 9111330, delete717755
discardedoperations:
 insert 348, delete mark 0, delete 0
Hash table size50999537, node heap has 70273 buffer(s)
3330.12 hashsearches/s, 946.55 non-hash searches/s


seg size当前插入缓冲页41071,free list len空闲队列长度41069 ,insert插入的记录数133199。

写操作密集的情况下插入缓冲占缓冲过大影响其他操作

二次写:当宕机时,数据库正在写一个页,然而这个页只写了磁盘一部分(部分写失效),导致部分数据丢失。然而重做日志无法恢复,因为重做日志是记录对页的物理操作,然而页已经损坏。因此在重做日之前,需要一个页的副本。

Doublewrite两部分组成:内存中的Doublebuffer(大小为2M)和物理磁盘上的共享表空间连续的两个区。当缓冲池脏数据刷新时,不是直接写到磁盘,而是先写到二次写缓冲区,然后再分两次写到两次写磁盘区,最后将脏数据从缓冲区直接刷新到磁盘。(二次写都是顺序写,速度快,减少了随机写时间长引起的宕机写失效的风险)。

宕机后的恢复,在共享空间中读取二次写改页的副本,拷贝到表空间文件,在做重做日志。
如果有多台从库,innodb_doublewrite 功能可以不启动。

自适应哈希索引:哈希是一种非常快的查找方法,常用于连接操作。Innodb根据访问的频率为某些也建立哈希索引。读写可以提高2倍的速度,连接可以提高5倍。哈希索引只能用于等值查询。

-------------------------------------
INSERT BUFFER ANDADAPTIVE HASH INDEX
-------------------------------------
3330.12 hashsearches/s, 946.55 non-hash searches/s


可以看出使用和没使用哈希索引的效率

五、启动关闭恢复

innodb_fast_shutdown
0
造成所有操作才关
1不需要完成full purge,merge insert buffer操作 缓冲池的数据刷新到磁盘
2表示都不完成 只需写入日志文件 
当数据库设为2或非正常关机 mysql在启动时会对表恢复
innodb_force_recovery
默认0 恢复执行所有所有恢复操作
有时我们知道如何去恢复,不需要Innodb自行回滚 回滚时间很长,我们可以将innodb_force_recovery不设为0,把表删了从备份中将数据导入表
>0不能做dml语句
实例未提交以及killMysql进程,没提交的回滚

2015-11-1616:59:33 13071 [Note] InnoDB: The log sequence numbers 1833451 and 1833451 inibdata files do not match the log sequence number 210684564 in the ib_logfiles!
2015-11-1616:59:33 13071 [Note] InnoDB: Database was not shutdown normally!
2015-11-1616:59:33 13071 [Note] InnoDB: Starting crash recovery.
2015-11-1616:59:33 13071 [Note] InnoDB: Reading tablespace information from the .ibdfiles...
2015-11-1616:59:33 13071 [Note] InnoDB: Restoring possible half-written data pages 
2015-11-1616:59:33 13071 [Note] InnoDB: from the doublewrite buffer...
InnoDB:1 transaction(s) which must be rolled back or cleaned up
InnoDB:in total 2 row operations to undo
InnoDB: Trx idcounter is 184320
InnoDB: Last MySQLbinlog file position 0 137539294, file name mysqlbin.000016
2015-11-1616:59:33 13071 [Note] InnoDB: 128 rollback segment(s) are active.
InnoDB: Startingin background the rollback of uncommitted transactions
2015-11-1616:59:33 7f8863a73700  InnoDB: Rollingback trx with id 183970, 2 rows to undo
2015-11-1616:59:33 13071 [Note] InnoDB: Waiting for purge to start
2015-11-1616:59:33 13071 [Note] InnoDB: Rollback of trx with id 183970 completed

 


 第三章 文件

一、参数文件与日志文件 


查看参数show variables的信息存储在information_schema.GLOBAL_VARIABLES
参数分动态和静态参数,动态意味着在实例中可以改变
有些参数只能会话修改autocommit,有些整个实例都会生效,但此会话不生效innodb_support_xa,可以会话和实例内都生效read_buffer_size 。
日志文件
错误日志 二进制日志 慢查询日志 查询日志
慢查询 long_query_time查看阀值是大于这个阀直,可以精确到微妙 
log_queries_not_using_indexes 将没走索引的记录记录来 

Mysqldumpslow用于慢查询日志解析

mysqldumpslow -sat -t 5 /opt/mysql/3306/data/db-slave-1-11-slow.log 
Reading mysql slowquery log from /opt/mysql/3306/data/db-slave-slow.log
Count: 1  Time=876.78s (876s)  Lock=0.00s (0s)  Rows=0.0 (0), admin[admin]@[192.168.186.32]
  update monitor_2015_07_03 setplayer_lost_cash = (select sum(a.lost_cash_of_day) fromsanguo_11.players_activity_logs a where a.log_date='S' andmonitor_2015_07_03.player_id=a.player_id)

-s at 按平均时间最长的排序-t 5显示前5位  Count: 1 Time=876.78s (876s) 一共有1条,平均时间为876.78秒
log_output 指定慢查询输出格式可以table也可以file,table模式可以在mysql.slow_log表中查找(被死锁的语句不会写入慢查询日志)

二、二进制日志

max_binlog_size 二进制日志容量多大开始切换新日志
binlog_cache_size 事务未提交时会将其写在cache里,提交写到二进制日志,一个线程一个事务,如果这值太小会将此缓存的数据写入一个临时文件
那多少为适合? Binlog_cache_use 记录了使用二进制日志的次数Binlog_cache_disk_use记录了临时文件写二进制的次数 =0是合适的
Binlog_Do_DB
 Binlog_Ignore_DB过滤写入二进制的数据库
Slave有这选项就会拉来这些db但在binlog中不执行和Replicate_Ignore_DB 一个意思。此参数的获取通过show slave/master status获取  

log_slave_updates选项,默认不开启情况下slave不将同步操作写进binlog日志的,当需要主从从时,第二个从库需要第一个从库的binlog。所以这时需要启动该选项。
binlog_format为mixed一般用statement,当一些不确定函数如user()当前登录用户,这种动态语句 
Row格式

当insert时

mysql> insertinto q values(20,11);
### INSERT INTO`t1`.`q`
### SET
###   @1=20 /* INT meta=0 nullable=0 is_null=0 */
###   @2=11 /* INT meta=0 nullable=1 is_null=0 */


当delete时

mysql> delete *from a;
### DELETE FROM`t1`.`a`
### WHERE
###   @1=1 /* INT meta=0 nullable=1 is_null=0 */
### DELETE FROM`t1`.`a`
### WHERE
###   @1=2 /* INT meta=0 nullable=1 is_null=0 */
### DELETE FROM`t1`.`a`
### WHERE
###   @1=1 /* INT meta=0 nullable=1 is_null=0 */
### DELETE FROM`t1`.`a`
### WHERE
###   @1=1 /* INT meta=0 nullable=1 is_null=0 */
### DELETE FROM`t1`.`a`
### WHERE
###   @1=1 /* INT meta=0 nullable=1 is_null=0 */

三、innodb引擎文件

Frm可以查看视图定义。

create view q1select * from q;
cat/opt/mysql/3306/data/t1/q1.frm
TYPE=VIEW
query=select`t1`.`q`.`id` AS `id`,`t1`.`q`.`b` AS `b` from `t1`.`q`
md5=14285012a6aa421fccda65e5a48c0b93
updatable=1
algorithm=0
definer_user=root
definer_host=localhost
suid=2
with_check_option=0
timestamp=2015-11-1703:04:04
create-version=1
source=select *from q
client_cs_name=utf8
connection_cl_name=utf8_general_ci
view_body_utf8=select `t1`.`q`.`id` AS`id`,`t1`.`q`.`b` AS `b` from `t1`.`q`

ibd路径和大小通过innodb_data_home_dir ,innodb_data_file_path  来定义 。

innodb_data_file_path| ibdata1:1000M;ibdata2:1000M:autoextend
-rw-rw---- 1 mysqlmysql 1000M Nov 17 11:12 ibdata1
-rw-rw---- 1 mysqlmysql  4.6G Nov 17 11:11 ibdata2

可以看到,当是初始化后ibdata1的容量就为1000M,当容量用满时只有ibdata2是自动增长的

innodb_file_per_table,打开后该表空间存数据,索引和插入缓冲信息。其余在共享表空间 

重做日志:innodb_log_group_home_dir存储位置,innodb_log_file_size重做日志大小innodb_log_files_in_group组内有多少日志文件 innodb_mirrored_log_groups有多日志文件组,1没有镜像 


你可能感兴趣的:(MySQL技术内幕)