标签:
2015-3-16 11:02:18
--------------------------------------------------------------------------------
innodb最佳实践
1.主键尽可能小,避免给Secondary index带来过大的空间负担
2.避免全表扫描,因为会使用表锁
3.尽可能缓存所有的索引和数据,提高响应速度
4.在大批量小插入的时候,尽量自己控制事务而不要使用autocommit自动提交
5.合理设置innodb_flush_log_at_trx_commit参数值,不要过度追求安全性
6.避免主键更新,因为这会带来大量的数据移动
############################################
打开监控 status
create table innodb_monitor(a int);
############################################
show engine innodb status\G; ---只打印64K 信息。多余的会截断。
完整的信息:
1.mysqld pid 25424
2./proc/25424/fd下
3.搜索文件 ll|grep
############################################
2.log buffer ---顺序读写
WAL = write-ahread-logging 预写日志
磁盘:
随机读写 --数据文件(一般都是,insert 可能是顺序)
顺序读写 --log
############################################-
ACID
atomicity 原子性
consistency 一致性
isolation 隔离性
durability 持久性
############################################
Innodb事务隔离级别
READ UNCOMMITED
可以看到其他事务未提交的数据。
事务1更新了数据还未提交,但是事务2居然能看到更新后的数据!
这是脏读。
READ COMMITED
能看到其他事务提交的数据。
事务1进行select,事务2进行更新并提交,事务1再select居然会看到和之前不同的数据!
这是不可重复读。
REPEATABLE READ --可重复读
一个事务里的开始点的select和任何时刻select看到的数据一样。 --使用undo
phantom read --幻读
MVCC解决了幻读
SERIALIZABLE
读操作会隐式的加S锁,保证不同事务之间互斥。保证串行 --同时同一对象只能一个读/写操作
############################################
开启事务:
begin;
start transaction;
set autocommit=0;
结束事务:
commit;
rollback;
还原点:
savepoint p1;
rollback to p1;
############################################
log sequence number =LSN ==>scn
############################################
innodb_file_per_table
on:独占表空间 --每个表一个文件
off:共享表空间
innodb_data_file_path=ibdata1:50M;ibdata2:50M:autoextend
autoextend --只支持最后一个文件
innodb_data_home_dir | /home/mysql/mysql5/var
############################################
查找某一行过程:
通过secondary index 找到 pk值 ,根据pk值 去cluster index 通过primary key匹配, 查找对应的page ,page顺序匹配row。
############################################
update t set c=20 where a=100 --行排他锁
key value
100 10
100 11
如果匹配多行,会逐行进行匹配
会锁 匹配行 聚集索引和辅助索引 --防止别人更新。
############################################
create table test1(id int,name1 varchar(300),name2 varchar(300),name3 varchar(500))charset=latin1 engine=innodb;
create index test1_name on test(name1,name2,name3);
此时给出warning:Specified key was too long;max key length is 767 bytes.
得出的结论是:对于创建innodb的组合索引,如果各个列中的长度不超过767,则不再计算所有列的总长度,如果有超过767的,则给出报警,索引最后创建成功,但是对于超过767字节的列取前缀索引;对于innodb的单列索引,超过767的,给出warning,最终索引创建成功,取前缀索引(取前255字节)。
----------------------------------------
create table test(id int,name1 varchar(300),name2 varchar(300),name3 varchar(500))charset=latin1 engine=myisam;
create index test_name on test(name1,name2,name3);
此时报错:Specified key was too long;max key length is 1000 bytes.
得出的结论是:对于myisam表,如果创建组合索引,所创建的索引长度和不能超过1000 bytes,否则会报错,创建失败;对于myisam的单列索引,最大长度也不能超过1000,否则会报警,但是创建成功,最终创建的是前缀索引(取前333个字节)。
############################################
数据页分类
system 系统页
trx_system 事务系统数据 ---也是数据页
inode 索引节点 --中间节点
index B+树叶节点
ibuf_bitmap insert buffer 位图
ibuf_index insert buffer 树叶节点
undo_log undo log页
file_space_header 文件页头 --是数据页 主要用lru list定位
allocated 新分配的页
blob blob页
unknown 未知页
根节点/中间节点 都是数据页,存放数据 需要加载到内存中
############################################
行格式
Antelope(compact,redundant)
Barracuda(compressed,dynamic) 新版本尽量使用新格式。
############################################
行头--
is_deleted 标志位 ---标志是否被删除,实际没有删除
Record hdr
Trx ID
Roll ptr
Fld ptrs
overflow-page ptr
..Field values
--------------------------------------------------------------------------------
compact format --prefix(768B)
Dynamic format --20 bytes;
############################################
文件头 (file header) --lsn/指向上下节点
页头 (page header) --
上确界,下确界 (infimun+suprenum records)
用户记录 user records
空闲空间 free space
数据页目录 page directory
页尾 file trailer --lsn
############################################
ARIES 恢复机制
----------------------------------------
实现的三个原则
1.WAL -- write ahead logging
2.redo repeating history during redo
3.undo logging changes during undo
############################################
redo log
1.混合记录
2.记录every operation
3.format
spaceid pageno offset operationType changes on that page
====rowid
4.delete只需记录 operationtype 不记 notes
############################################
undo log
1.format
primary key valus | old trx id |old values on that row
作用
1.rollback
2.读一致性
3.实例恢复。
############################################
原子性:
操作:
update t1 set b=20 where a=10 --key(a) key(b)
原值 b=15
key(a)
10 1
10 2
11 3
key(b)
15:1
15:2
key value --存主键
1.先写data
2.后写key(b)
通过 key(a) 找到a=10 的行,修改行,然后根据pk (value) 匹配key(b) 修改key(b) 的key值。
############################################
innodb_flush_log_at_trx_commit
0:每1秒钟,log buffer写入log file并同步,但commit不做任何事 ---性能最好
一旦宕机,丢失过去1秒更新
1:默认,每次commit时log buffer写入log file并同步 ---commit 过多导致 threads_running 飙升,IO/cpu wait飙升。 --最安全
(交易系统使用)
2:每次commit时log buffer写入log file,但不同步。同步发生在每一秒(进一步取决于OS进程调度)
一旦OS或机器宕机,丢失过去1秒更新
mysqld挂了,不丢数据。 --数据在内存中。
############################################
整个mysql只有一张hash表
每次更新hash表都会添加一个全局排他锁,大批量频繁的访问一张表会导致AHI堆积。 如果堆积到6分钟最有,mysql会crash掉。
导致AHI堆积的条件
1.单位扫描行数过大(每次100W) --OLAP/CRM/ERP
2.使用辅助索引
解决方法:
1.分散读
2.kill查询
3.升级到percona版本。
############################################
宕机恢复损坏的页
两部分:doublewrite buffer和共享表空间的doublewrite
两个连续的extent 共2m。 ---单独的区域。
doublewrite buffer-->共享表空间的doublewrite(连续的空间,顺序写).然后doublewrite buffer-->ibd
############################################
刷盘
1.每一秒操作
不管事务是否提交,刷新log buffer 到磁盘
合并 insert buffer页(I/O负载较小时)
最多刷新100个buffer pool脏页到磁盘
innodb_max_dirty_pages_pct 默认90
2.每10秒操作
最多刷新100个buffer pool脏页到磁盘
最多合并5个insert buffer页
刷新log buffer
删除无用undo页
产生一个checkpoint(fuzzy) ---模糊检查。
全量检查点--正常关库时产生。
############################################
innodb_fast_shutdown
0:full purge and full insert buffer merge
(install innodb-plugin)
1:默认,不做上述操作,只刷新部分脏页到磁盘。fast
2: no full purge
no full insert buffer merge
no dirty page flush
only flush redo
提交的事务不会丢失,重启后进行实例恢复
full purge ---删除undo 删除is_deleted标志为1的行。
############################################
mysqld restart…
1.接受任何连接之前,应用redo,重做提交的事务
(若crash之前dirty page被全部刷新到磁盘,跳过1)
2.回滚未提交的事务
3.将需要重做/回滚的相关数据从共享表空间读出,进行insert buffer merge ---重启慢的原因。
4.purge:清楚已经被标记为delete的记录
以上,仅2为实例恢复特有
############################################
相关的选项有:
#InnoDB存储数据字典、内部数据结构的缓冲池,16MB 已经足够大了。
innodb_additional_mem_pool_size = 16M
#InnoDB用于缓存数据、索引、锁、插入缓冲、数据字典等
#如果是专用的DB服务器,且以InnoDB引擎为主的场景,通常可设置物理内存的50%
#如果是非专用DB服务器,可以先尝试设置成内存的1/4,如果有问题再调整
#默认值是8M,非常坑X,这也是导致很多人觉得InnoDB不如MyISAM好用的缘故
innodb_buffer_pool_size = 4G
#InnoDB共享表空间初始化大小,默认是 10MB,也非常坑X,改成 1GB,并且自动扩展
innodb_data_file_path = ibdata1:1G:autoextend
#如果不了解本选项,建议设置为1,能较好保护数据可靠性,对性能有一定影响,但可控
innodb_flush_log_at_trx_commit = 1
#InnoDB的log buffer,通常设置为 64MB 就足够了
innodb_log_buffer_size = 64M
#InnoDB redo log大小,通常设置256MB 就足够了
innodb_log_file_size = 256M
#InnoDB redo log文件组,通常设置为 2 就足够了
innodb_log_files_in_group = 2
#启用InnoDB的独立表空间模式,便于管理
innodb_file_per_table = 1
#启用InnoDB的status file,便于管理员查看以及监控等
输出SHOW ENGINE INNODB STATUS内容到innodb_status.pid ,数据库关闭是会删除
--innodb-status-file = 1
tx_isolation =REPEATABLE-READ
#设置最大并发连接数,如果前端程序是PHP,可适当加大,但不可过大
#如果前端程序采用连接池,可适当调小,避免连接数过大
max_connections = 60
#最大连接错误次数,可适当加大,防止频繁连接错误后,前端host被mysql拒绝掉
max_connect_errors = 100000
#设置慢查询阀值,建议设置最小的 1 秒
long_query_time = 1
#设置临时表最大值,这是每次连接都会分配,不宜设置过大 max_heap_table_size 和 tmp_table_size 要设置一样大
max_heap_table_size = 96M
tmp_table_size = 96M
#每个连接都会分配的一些排序、连接等缓冲,一般设置为 2MB 就足够了
sort_buffer_size = 2M
join_buffer_size = 2M
read_buffer_size = 2M
read_rnd_buffer_size = 2M
#建议关闭query cache,有些时候对性能反而是一种损害
query_cache_size = 0
#如果是以InnoDB引擎为主的DB,专用于MyISAM引擎的 key_buffer_size 可以设置较小,8MB 已足够
#如果是以MyISAM引擎为主,可设置较大,但不能超过4G
#在这里,强烈建议不使用MyISAM引擎,默认都是用InnoDB引擎
key_buffer_size = 8M
#设置连接超时阀值,如果前端程序采用短连接,建议缩短这2个值
#如果前端程序采用长连接,可直接注释掉这两个选项,是用默认配置(8小时)
interactive_timeout = 120
wait_timeout = 120
############################################
select * from t where id=10 id --pk
select a from t where id=10
内存 一样
IO 一样
网络 不一样
############################################
默认存储引擎InnoDB plugin
原InnoDB只有一个Undo Segment,最多支持1023的并发;现在有128个Segments,支持128K个并发(同样,解决高并发带来的事务回滚)
Innodb_thread_concurrency
默认为0,线程并发数无限制,可根据具体应用设置最佳值 不要更改 已经是最佳
2×cpu+disk数
Innodb_io_capacity
可以动态调整刷新脏页的数量,改善大批量更新时刷新脏页跟不上导致的性能下降问题。Default:200,跟硬盘的IOPS有关。
insert buffer merge:
innodb_io_capacity * 5%
flush dirty page:
innodb_io_capacity * 100%
############################################
innodb_read_io_threads 阈值:1-64 cpu core的一半。
innodb_write_io_threads 阈值:1-64
############################################
自适应刷新脏页
InnoDB plugin刷新脏页规则
脏页数量超过innodb_max_dirty_pages_pct
Ib_logfile写满
机器空闲
以上情况下innodb_buffer_pool的脏页会被刷盘。但是,若写操作非常频繁,ib_logfile切换次数也会很频繁,大批量脏页刷盘造成大的磁盘IO,系统整体性能会受到不小影响。
innodb_adaptive_flushing自适应刷新脏页
根据ib_logfile生成速度和刷新频率将脏页刷盘,即使没有达到innodb_max_dirty_pages_pct也可以刷盘,可以避免大批量IO 提高系统整体性能。
############################################
热数据存活更久
Innodb_buffer_pool LRU
sublist of new blocks && sublist of old blocks
查询命中,直接返回 ;否则从磁盘读入sublist of old blocks 通过LRU算法踢出旧数据页。而mysqdump或select * from table等做全表扫描会将sublist of new blocks的热数据页踢出,导致频繁磁盘IO,影响系统整体性能。
MySQL5.5.X解决方案:
innodb_old_blocks_pct 控制进入缓冲区的数量,全表扫描设置小一些;适合内存表查询,设置大一些。
innodb_old_blocks_time 暂缓移动到new blocks,让热数据不会被马上踢出。
############################################
瓶颈:innodb_buffer_pool达到数十G 会造成某个线程正在更新缓冲池而其他线程等待。
buffer pool多实例
MySQL5.5.X解决方案
innodb_buffer_pool_instances 参数增加innodb_buffer_pool实例个数,大大降低buffer pool的mutex争抢过热情况
利用hash函数将读取缓存的数据页随机分配到缓冲池 每个缓冲池实例分别管理free list & flush list & LRU
Innodb_buffer_pool_size必须大于1G,该参数才有效
最多支持64个innodb_buffer_pool实例 一般设置8或16
静态变量
############################################
重新支持组提交
事务提交,先写日志后刷盘;多用户同时提交,若按顺序把写入事务日志页刷盘,会造成多次IO操作,降低IOPS
MySQL5.5恢复组提交方式刷盘,将多用户提交的事务merge,然后一次性刷盘,大大提高了IO吞吐量
Sync_binlog必须为0,不做强制刷盘 ---不安全,但性能超好。
############################################
半同步Replication
确保主库和至少一台从库之间的数据一致性和冗余
至少有一台从库在主库进行事务处理前确认更新已经到达其Relay Log
出现超时,主库必须暂时切换到异步复制模式重新复制,直到一台设置为半同步复制模式的从库及时收到信息
############################################
Relay Log 自我修复
relay_log_recovery
slave从库的Relay Log损坏导致部分Relay Log未处理,则自动放弃所有未执行的Relay Log 并重新从主库获取日志
默认relay_log_recovery为0 ,建议开启该功能
############################################
Crash recovery
原来的恢复策略需要不断检查InnoDB的buffer pool,以避免被存储恢复用的redo log的hash table打满,O(n*m)的时间复杂度;
MySQL5.5.X引入红-黑树做插入排序的中间数据结构,时间复杂度大大降低,减少恢复时间;
Crash Recovery
一、mysql crash recovery需要mysql上层与InnoDB存储引擎协作进行恢复。必须保证InnoDB的恢复,与上层mysql binlog一致,如此, 主库崩溃恢复之后,其数据能够保证与备库是一致的;
二、binlog中commit事务的trx_id,在函数log.cc::TC_LOG_BINLOG::recover中读取并构造出来。然后通过调用流程,一直传递给handler.cc::xa_recover_handlerton函数,info->commit_list;
三、InnoDB层面的innobase_xa_recover函数,找出存储层面已经prepare,但是没有commit的事务id数组,通过调用返回给handler.cc::xa_recover_handlerton函数,info->list;
四、handler.cc::xa_recover_handlerton函数,比较两个trx_id数组(info->commit_list组织为hash表,在hash表中定位info->list中的事务);
五、如果info->list中的事务id在commit_list中存在,则调用innobase_commit_by_xid函数重新提交事务;
六、如果info->list中的事务id在commit_list中不存在,则调用innobase_rollback_by_xid函数回滚事务;
七、完成以上操作,crash recovery成功,数据库恢复到崩溃前的状态;
############################################
InnoDB严格检查模式
MySQL5.5.X可以开启InnoDB严格检查模式
即当create table & alter table & create index 的SQL有语法错误 直接抛出错误而不会有警告,直接将问题扼杀在萌芽状态
参数默认值OFF,建议开启
支持动态开启
set global innodb_strict_mode=1
其他
快速在线索引创建
Buffer pool数据页GC逻辑从主线程剥离
扩展数据变化缓冲innodb_change_buffering delete,insert
----------------------------------------
主要是innodb层变化。 提成3倍性能。
############################################
1.rpm包安装
/usr/bin --客户端程序和脚本
/usr/sbin --mysqld服务器程序
/var/lib/mysql --日志文件和数据文件
/usr/share/doc/packages --文档
/usr/include/mysql --头文件
/usr/lib/mysql --库文件
/usr/share/mysql --错误消息和字符集文件
/usr/share/sql-bench --基准程序
############################################
语法语义解析
SQL:select a from t1 where id=10 and name=‘a‘
解析成语法树
command =>select
select list =>{a,b,c}
from table =>t1
conds => and
id name
10 ‘a‘
optimizer --优化器
投影(select a,b,c) 选择(where) 链接(from t1,t2),差集--sql原理
1.逻辑优化
比如 and 1=1 ,会被逻辑优化掉。
2.物理优化
基于实际的行数做代价估算。
链接顺序,每个表内的访问方式
1.连接顺序
2.表内扫描方式
############################################
mysql 每行多一个字符记录是否为空
default null 每行多一个字符记录是否为空
default not null 节省空间
############################################
数据块(面试)
inode --
[root@mysql ~]# stat anaconda-ks.cfg --inode信息
File: `anaconda-ks.cfg‘
Size: 1714 Blocks: 8 IO Block: 4096 regular file
Device: 802h/2050d Inode: 930919 Links: 1
Access: (0600/-rw-------) Uid: ( 0/ root) Gid: ( 0/ root)
Access: 2014-06-21 07:07:54.536079654 +0800
Modify: 2014-06-21 06:57:50.936932130 +0800
Change: 2014-06-21 06:58:20.836122247 +0800
[root@mysql ~]# ls -i anaconda-ks.cfg
930919 anaconda-ks.cfg
############################################
ddl(crate drop truncate) 不需要走优化器
############################################
server层日志:
1.general log --所有SQL
2.binlog和binlog索引 --所有更新(insert、update、delete)
3.slow log --所有慢查询
4.error log --alert日志
5.relay log和relay log索引文件 --主从复制中继
存储引擎层日志
1.innodb 的redo log --innodb 所有更新
2.innodb 的undo (ibdata中) --innodb 的undo
############################################
只有commit的时候才会记录到binlog
commit之前都在binlog cache中,commit时,会把它写到磁盘。
记录数据库全部的变更信息 --select不包括
############################################
Event_time每秒第一次query打印
Query发出时记录
错误的,失败的,成功的均会记录
数据库的流量日志
----------------------------------------
additional usage?
1.安全
2.查找执行历史。
3.审计
4.流量分析
5.模拟执行
############################################
flush logs; --产生的新的binlog
3.日志切换策略
使用索引来循环文件,在以下条件将循环至下一个索引,生成一个新的文件。
a.服务器重启
c.日志达到了最大日志长度max_binlog_size
d.日志被刷新 flush logs;
6.1、如何清除binlog
--使用下面的两个命令
PURGE {MASTER|BINARY} LOGS TO ‘log_name‘ //log_name不会被清除
PURGE {MASTER|BINARY} LOGS BEFORE ‘date‘ //date不会被清除
############################################
3.写机制
sync_binlog =1
默认0:OS调度决定。
N:每N事务写入binlog cache,用fdatasync()同步
生产上设置 1,
值为1是最安全的选择,因为崩溃时,你最多丢掉二进制日志中的一个语句/事务
对于 myisam 每条相当于一个事务。
当事务提交后,Mysql仅仅是将binlog_cache中的数据写入binlog文件,但不执行fsync之类的磁盘,同步指令通知文件系统将缓存刷新到磁盘,而让Filesystem自行决定什么时候来做同步,这个是性能最好的。
############################################
底层函数:
fsync
fdatasync
o_direct
############################################
如果binlog采用了 MIXED 模式,那么在以下几种情况下会自动将binlog的模式由 SBR 模式改成 RBR 模式。
. 当DML语句更新一个NDB表时
. 当函数中包含 UUID() 时
. 2个及以上包含 AUTO_INCREMENT 字段的表被更新时
. 行任何 INSERT DELAYED 语句时
. 用 UDF 时
. 视图中必须要求运用 RBR 时,例如建立视图是运用了 UUID() 函数
使用自定义函数
############################################
另外,针对系统库 mysql 里面的表发生变化时的处理准则如下:
如果是采用 INSERT,UPDATE,DELETE 直接操作表的情况,则日志格式根据 binlog_format 的设定而记录
如果是采用 GRANT,REVOKE,SET PASSWORD 等管理语句来做的话,那么无论如何 都采用 SBR 模式记录。
############################################
| log_slow_queries | ON | ---5.6弃用
| slow_query_log | ON | --启用
| slow_query_log_file | /home/mysql/mysql1/log/slow.log | --指定位置
| long_query_time | 1.000000 | ---阈值(Default 10)
| log_queries_not_using_indexes | OFF | ---记录noindex语句
| log_output | FILE |---TABLE(mysql.general_log,slow_log), FILE, or NONE
---仅指定日志记录的类型 只对general query log and slow query log output
############################################
| innodb_file_per_table | ON
----------------------------------------
1.--独占表空间 --每个表都占有一个表空间/一个文件
2.减少操作对系统表空间的开销(DROP TABLE or TRUNCATE TABLE.)
############################################
log_bin_trust_function_creators=1; ---非super权限可以创建trigger
############################################
3.thread_cache_size
不立即生效--下次有连接被关闭时生效。
连接关闭时,1.如果cache有空间,继续缓存该thread,以备重用;2如果没有空间,销毁该thread。此时缓存中的线程数和使用的内存,不会立刻减少;只有在新的连接删除缓存中的一个线程并使用后才会减少。
(关闭连接时,在缓存中增加thread,
创建新连接时,从缓存中删除thread)
############################################
innodb_flush_method这个参数控制着innodb数据文件及redo log的打开、刷写模式,对于这个参数,文档上是这样描述的:
有三个值:fdatasync(默认),O_DSYNC,O_DIRECT
默认是fdatasync,调用fsync()去刷数据文件与redo log的buffer
为O_DSYNC时,innodb会使用O_SYNC方式打开和刷写redo log,使用fsync()刷写数据文件
为O_DIRECT时,innodb使用O_DIRECT打开数据文件,使用fsync()刷写数据文件跟redo log
innodb_flush_log_at_trx_commit参数确定日志文件何时write、flush。
innodb_flush_method则确定日志及数据文件如何write、flush。
O_DSYNC:使用O_SYNC打开和刷新log文件,使用fsync()刷新数据文件。
O_DIRECT:使用O_DIRECT打开数据文件,使用fsync()刷新日志文件和数据文件。
Open log Flush log Open datafile Flush data
Fdatasync fsync() fsync()
O_DSYNC O_SYNC fsync()
O_DIRECT fsync() O_DIRECT Fsync()
############################################
innodb_flush_log_at_trx_commit
--------------------------------------------------------------------------------
配置项说明
0
每秒刷新一次,并且把log buffer写到log file(磁盘),但是commit时不做任何事
(执行是由mysql的master thread线程来执行的。主线程中每秒会将log buffer写入磁盘的REDO LOG中。不论事务是否已经提交。)默认的日志文件是ib_logfile0,ib_logfile1
1
每次提交事务的时候,都会将log buffer刷写到持久化存储。
保证不丢失任何已经提交的事务,除非磁盘或者操作系统是伪刷新。
2
如果设为2,每次提交事务都会写日志,但并不会执行刷的操作。每秒定时会刷到日志文件。
只有在操作系统崩溃或者断电的时候才会丢失最后1秒的数据,mysql进程挂了,不丢任何事物。
备注:
A.把log buffer写到log file
把数据从innodb的buffer转移了OS的buffer,还在内存中,并没有真正写到磁盘
B.把日志刷新到持久化存储
innodb请求OS把数据刷出缓存,并且写到磁盘。
最佳配置:设为1 且把日志文件放到有电池保护的写到缓存的RAID卷中
############################################
刷写的概念
刷写其实是两个操作,刷(flush)和写(write),区分这两个概念(两个系统调用)是很重要的。在大多数的操作系统中,把Innodb的log buffer(内存)写入日志(调用系统调用write),只是简单的把数据移到操作系统缓存中,操作系统缓存同样指的是内存。并没有实际的持久化数据。
############################################
sync_binlog
----------------------------------------
刷新binlog的数目
双1模式,即:innodb_flush_log_at_trx_commit = 1,sync_binlog = 1,这样主备的数据是一致的,不会丢失数据。
############################################
表链接
1.左链接
2.右链接
3.全链接
----------------------------------------以上是外链接。
4.内链接
5.自然链接
6.自链接
7.笛卡尔积连接 --没有连接条件
############################################
执行计划中有 filesort 就会进行磁盘文件排序
有这个误区其实并不能怪我们,而是因为 MySQL 开发者在用词方面的问题。filesort 是我们在使用 explain 命令查看一条 SQL 的执行计划的时候可能会看到在 “Extra” 一列显示的信息。实际上,只要一条 SQL 语句需要进行排序操作,都会显示“Using filesort”,这并不表示就会有文件排序操作。
############################################
id如果相同,可以认为是一组,从上往下顺序执行;在所有组中,id值越大,优先级越高,越先执行
############################################
mysql> create table innodb_lock_monitor(a int); --打开lock监控
----------------------------------------
1.锁定粒度:
表级锁
MyISAM,memory,innodb,BDB
行级锁
innodb(默认)
页级锁
BDB
----------------------------------------
2.模式
X S IX IS(意向共享)
3.实现算法
innodb 间隙 next-key
############################################
innodb
1.粒度
表 行
2.模式
s/x/is/ix/auto_inc(可视为x的一种)
3.算法
1.record
2.gap
3.next_key
############################################
show status like ‘%table_locks_immediate%’;
立即获得锁
show status like ‘%table_locks_waited%’;
等待锁
############################################
innodb事务
1.ACID
2.并发访问带来的读一致性问题:脏读/不可重复读/幻读
3.如何解决?
读之前加S,再读
多版本控制(MVCC)
4.innodb_lock_monitor
create table innodb_lock_monitor(a int); --开启锁监控。
############################################
lock mode
行锁
1.S锁
2.X锁
表锁 ---表级意向锁
1.IS锁
2.IX锁
锁住所有行及间隙。
在加行锁之前必须先获得表级意向锁,否则等待innodb_lock_wait_timeout
超时后根据innodb_rollback_on_timeout决定是否回滚事务
############################################
innodb_autoinc_lock_mode:
0:(traditional)
旧的表锁方式,不推荐(5.0系统)
1:(consecutive)
默认,
对于simple inserts,用mutex对内存中的计数器累加。
对于bulk inserts,使用传统的auto-inc锁。
safe for binlog using statement
2:(interleaved)
对于所有insert,用mutex实现自增,性能最大化
unsafe for binlog using statement --binlog容易出错,可以使用row模式。
建议使用row-based
############################################
GEN_CLUST_INDEX --6字节 ---innodb表不定义主键时,自动生成的主键。
############################################
InnoDB行锁实现算法
通过对索引数据页上的record加锁
算法实现:
1.record lock:单行记录的锁
2.gap lock:间隙锁,锁定一个范围,不包括记录本身
3.next-key lock:(record lock)+(gap lock)
在tx_isolation=REPEATABLE-READ和innodb_locks_unsafe_for_binlog=off情况下, innodb默认算法
锁住间隙加上间隙边缘值的record
左开右闭 ( 3,7 ]
############################################
InnoDB逐行加锁,导致死锁
死锁产生的四个条件:
1.互斥条件:一个资源每次只能被一个进程使用;
2.请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放;
3.不剥夺条件:进程已获得的资源,在没使用完之前,不能强行剥夺;
4.循环等待条件:多个进程之间形成一种互相循环等待资源的关系
############################################
避免死锁:
1.加锁顺序一致
2.尽量基于primary或unique key更新数据 --锁住行数少
3.单次操作数据量不宜过多,涉及表尽量少
4.减少表上索引,减少锁定资源
############################################
read_rnd_buffer_size
根据索引信息读取表数据,根据排序后的结果集与表进行Join等等。
read_buffer_size
无法使用索引的情况下的全表扫描,全索引扫描等。
在这种时候,MySQL 按照数据的存储顺序依次读取数据块,每次读取的数据块首先会暂存在read_buffer_size中,当buffer 空间被写满或者全部数据读取结束后,再将buffer中的数据返回给上层调用者,以提高效率。
############################################
binlog_cache_size
缓存各种数据变更操作产生的binlog信息
超过binlog_cache_size,则使用磁盘临时文件
max_binlog_cache_size
Error:Multi-statement transaction required more than ‘max_binlog_cache_size‘ bytes of storage
--binlog cache不够用。
############################################
cache 磁盘--->内存 从磁盘中读入内存
buffer 内存--->磁盘 从内存中写入磁盘
############################################
若join buffer不够?
部分join返回output,清除,再放入。 ---根据结果集评估。
############################################
net_buffer_length
用于保存客户端线程的连接信息和返回客户端的结果集
mysqld结果集->net buffer->客户端
net_buffer_length为初始大小
最大max_allowed_packet
SQL结束后收缩回net_buffer_length
############################################
何时会产生临时表?
1.group by
2.多表链接 order by
3.order by 1 asc,2 desc
4.from后的子查询。
tmp_table_size
设置内存临时表的max size
no,应该是max(tmp_table_size,max_heap_table_size)
当超过限制时,会转化为MyISAM磁盘表
############################################
线程共享:query_cache_size --第一层缓存。
---只针对于 select
---update/delete/insert/truncate ---都会导致QC刷新。
--用于读多写少。 --论坛系统。
############################################
sql 进入解析器之前 先查 query_cache_size。
memory cache -- 存在程序和数据块之间
sql -->qc(是否存在相同sql/如果存在直接返回结果。)-->解析器/优化器-->innodb -->buffer pool(相关数据页是否存在)-->磁盘读取到内存。
############################################
table_open_cache
所有线程打开的表的缓存(缓存fd(文件句柄))
1..frm文件解析结果(MySQL 5.1)
2.存储引擎文件的fd
query->open_table()->table cache
flush tables; 关闭表缓存里的fd
用于关库之前,关闭fd
############################################
基本原则
尽量少 join
尽量少排序
尽量避免 select *
尽量用 join 代替子查询
尽量少 or
尽量用 union all 代替 union
尽量早过滤
避免类型转换
人为在column_name 上通过转换函数进行转换
由数据库自己进行转换
优先优化高并发的 SQL,而不是执行频率低某些“大”SQL
从全局出发优化,而不是片面调整
尽可能对每一条运行在数据库中的SQL进行 explain
############################################
system 表中仅有一行,即常量表
const 单表中使用pk/unique index
eq_ref 多表连接中使用pk/unique index
ref 使用普通索引
ref_or_null 条件中包含对NULL的查询
index_merge 索引合并优化
unique_subquery in的后面是一个查询主键字段的子查询
index_subquery in的后面是一个查询非唯一索引字段的子查询
range 单表中范围查询
index 全索引扫描
all 全表扫描
############################################
Extra
包含不适合在其他列中显示但十分重要的额外信息
a.Using index
该值表示相应的select操作中使用了覆盖索引(Covering Index)
############################################
使用索引能做什么
读索引
1.随机访问 --访问索引列 a=1
2.覆盖索引 --select idx_col
3.范围扫描 --索引列范围
############################################
key_length ---字节
定长 ---char,int,datetime ,not null 比null少一个字节(NULL的标记)
变长 ---varchar 1.长度信息(1bytes) 2.NULL的标记
字符 ---latin1编码一个字符一个字节,
gbk编码的为一个字符2个字节,
utf8编码的一个字符3个字节。
############################################
MySQL 表关联的算法是 Nest Loop Join,是通过驱动表的结果集作为循环基础数据,然后一条一条地通过该结果集中的数据作为过滤条件到下一个表中查询数据,然后合并结果。
EXPLAIN 结果中,第一行出现的表就是驱动表(Important!)
对驱动表可以直接排序,对非驱动表(的字段排序)需要对循环查询的合并结果(临时表)进行排序(Important!)
因此,order by ads.id desc 时,就要先 using temporary 了!
驱动表的定义
wwh999 在 2006年总结说,当进行多表连接查询时, [驱动表] 的定义为:
1)指定了联接条件时,满足查询条件的记录行数少的表为[驱动表];
2)未指定联接条件时,行数少的表为[驱动表](Important!)。
忠告:如果你搞不清楚该让谁做驱动表、谁 join 谁,请让 MySQL 运行时自行判断
小结果集驱动大结果集
优化的目标是尽可能减少JOIN中Nested Loop的循环次数,
以此保证:
永远用小结果集驱动大结果集(Important!)!
############################################
如果你看到以下现象,请优化:
出现了Using temporary;
rows过多,或者几乎是全表的记录数;
key 是 (NULL);
possible_keys 出现过多(待选)索引。
############################################
确保亲手查过SQL的执行计划,一定要注意看执行计划里的 possible_keys、key和rows这三个值,让影响行数尽量少,保证使用到正确的索引,
减少不必要的Using temporary/Using filesort;
不要在选择性非常差的字段上建索引
############################################
组合索引查询的各种场景
兹有 Index (A,B,C) ——组合索引多字段是有序的,并且是个完整的BTree 索引。
下面条件可以用组合索引查询:
A>5
A=5 AND B>6
A=5 AND B=6 AND C=7
A=5 AND B IN (2,3) AND C>5
下面条件将不能用组合索引查询:
B>5 ——查询条件不包含组合索引首列字段
B=6 AND C=7 ——查询条件不包含组合索引首列字段
下面条件将能用部分组合索引查询:
A>5 AND B=2 ——当范围查询使用第一列,查询条件仅仅能使用第一列
A=5 AND B>6 AND C=2 ——范围查询使用第二列,查询条件仅仅能使用前二列
############################################
组合索引排序的各种场景
兹有组合索引 Index(A,B)。
下面条件可以用上组合索引排序:
ORDER BY A ——首列排序
A=5 ORDER BY B ——第一列过滤后第二列排序
ORDER BY A DESC, B DESC——注意,此时两列以相同顺序排序
A>5 ORDER BY A ——数据检索和排序都在第一列
下面条件不能用上组合索引排序:
ORDER BY B ——排序在索引的第二列
A>5 ORDER BY B ——范围查询在第一列,排序在第二列
A IN(1,2) ORDER BY B ——理由同上
ORDER BY A ASC, B DESC ——注意,此时两列以不同顺序排序
############################################
索引合并的简单说明:
MySQL 索引合并能使用多个索引
SELECT * FROM TB WHERE A=5 AND B=6
能分别使用索引(A) 和 (B) 或 索引合并;
创建组合索引(A,B) 更好;
SELECT * FROM TB WHERE A=5 OR B=6
能分别使用索引(A) 和 (B) 或 索引合并;
组合索引(A,B)不能用于此查询,分别创建索引(A) 和 (B)会更好;
############################################
SUBQUERY:子查询中的第一个SELECT;
DEPENDENT SUBQUERY:子查询中的第一个SELECT,取决于外面的查询 。
换句话说,就是 子查询对 g2 的查询方式依赖于外层 g1 的查询。
############################################
1.如何设计授权和安全策略
权限最小化,管理权限不要给,process,file,super
集群内所有实例账号一致
避免使用通配符%
mysql初始用户删除,并给root赋予密码
select user,host,password from mysql.user;
避免用root用户启动mysqld
db账号按照程序端模块划分
1.程序读写账号
2.程序定时任务账号
3.监控和管理程序账号
4.同步账号
尽量使用ip来授权,why?
如果web和mysql在同一主机,--尽量使用socket链接
----------------------------------------
2.安全设置选项
--skip-networking
禁用TCP/IP连接,用剩下3种
--skip-name-resolve
禁用主机名方式验证客户端,localhost除外
host cache解析流程:
client_ip->server->host_cache(ip,hostname,error)
->ip->hostname in host_cache ---耗时
->resolved_ip==ip? yes: connect
no:aborted_connect
question:为什么只用ip授权?
1.skip-name-resolve缘故
2.防止DNS恶意篡改
--skip-grant-table ---用于root密码忘记,修改密码。
不加载权限表,所有用户完全权限登陆
可通过flush privileges或reload重新加载权限表
--local-infile=0
禁用load data local,在无远程load data生产环境建议设为0
load data local 可远程加载文件
load data 只能本机加载
--old-passwords
新的加密方位41位兼容老的密码加密方式16位
不建议开启
--safe-user-create
除非用户有对mysql.user的insert权限,否则不能用grant方式创建用户
--secure-auth
使得MySQL 4.1以前的客户端无法验证,防止旧密码连接
--skip-show-database
只允许有show databases权限的用户执行该语句
############################################
1.如何排查服务器堵塞了
1.connectors部分 ----网络慢 gone away ;并发过大
2.sql本身问题 ----sql过大(发送时过大),client/server 设置不一样,发过去是超过server最大值
mysql> show variables like ‘max_allo%‘;
+--------------------+----------+
| Variable_name | Value |
+--------------------+----------+
| max_allowed_packet | 67108864 |
+--------------------+----------+
3.cache --锁问题
4.解析器优化/解析器
5.存储引擎层 (内存池)innodb--buffer 磁盘读过大/锁争用
6.binlog/redolog 写
7.磁盘问题
############################################
create table t as select * from t1----不复制源表的 索引约束等。
create table t like t1 --t1/t表结构一致(有索引等),没有数据
############################################
排查问题思路
1.top cpu 内存 确认为mysqld
2.进入mysql 查看正在做什么
3.show processlist;
4.show engine innodb status \G;
############################################
innodb的锁是加在什么地方?
是加在数据页上的record 的 index上
----------------------------------------
索引过多:
1.优化器评估,花费更多
2.修改时,过慢
3.导致过多锁定资源
############################################
sed -i "s#/home/mysql/mysql#/home/mysql5/mysql1#g" my.cnf
############################################
1.utf-16:unicode的16位定长多字节编码方案,2个字节表示一个unicode字符
2.utf-8:unicode的8位变长多字节编码方案,使用1-3个字节表示一个unicode字符
############################################
问题排查:字符集问题。
1.html 字符集
webcontent --> apache(http字符集) --> java(字符集)-->中间件(字符集)-->mysql(字符集)--->磁盘
############################################
锁定状态
----------------------------------------
show global status like ‘%lock%’;
innodb_row_lock_waits --当前innodb的锁等待
table_locks_waited --服务器层锁等待
锁定的线程数
############################################
建议你在接手每一个集群之前,梳理好以下几点:
1.集群架构
2.mysql版本,部署机房
3.集群为多少前端模块提供服务,每个模块的开发人员负责人
4.集群流量情况,包括读写负载、峰值QPS、流量高峰期时段分布
5.集群的查询库和备库分布
6.是否有自动切换、中间件、虚ip等
7.与业务方的SLA和MTTR、MTBF约定
8.集群历史问题、目前主要瓶颈
############################################
数据碎片
1.行碎片(row fragmentation)
数据行被存储为多个地方的多个片段中。即使查询只从索引中访问一行记录,行碎片也会导致性能下降。
2.行间碎片(Intra-row fragmentation)
逻辑上顺序的页,或者行在磁盘上不是顺序存储的。
3.剩余空间碎片(Free space fragmention)
数据页中有大量的空余空间。导致服务器读取大量不需要的数据。
innodb不会出现行碎片,innodb会移动短小的行并重写到一个片段中。
############################################
主从复制选项
log-slave-updates
开启从库binlog,默认关闭,用于级联库
master-connect-retry
slave连不上主库时,重试时间间隔,默认60s
master-retry-count
最大重试次数
slave-net-timeout
每次重试的最长忍耐时间
read-only
设置只读,适用于从库
skip-slave-start
防止从库同步自动启动 --必须添加。
标签:
原文地址:http://www.cnblogs.com/afx1007/p/4378222.html