第一章 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没有镜像