结构和历史mysql
1. 隔离级别有四种:
READ UNCOMMITTED(未提交读),同事务中某个语句的修改,即便没有提交,对其余事务也是可见的。这个也叫脏读。
READ COMMITTED(提交读),另外一个事务只能读到该事务已经提交的修改,是大多数据库默认的隔离级别。可是有下列问题,一个事务中两次读取同一个数据,因为这个数据可能被另外一个事务提交了两次,因此会出现两次不一样的结果,因此这个级别又叫作不可重复读。这里的不同的数据包括虚读(两次结果不一样)和幻读(出现新的或者缺乏了某数据)。
REPEATABLE READ(可重复读),这个级别不容许脏读和不可重复读,好比MYSQL中经过MVCC来实现解决幻读问题。
SERIALIABLE(可串行化),这儿实现了读锁,级别最高。ios
2. 显示和隐式锁定:事务执行中,随时能够执行锁定,锁只有在COMMIT或ROLLBACK的时候才释放,并且全部的锁是同时释放的。这些锁定都是隐式锁定。也能够经过特定语句显式锁定,好比SELECT … LOCK IN SHARE MODE等。sql
3. MVCC(多版本并发控制):经过保存数据在某个时间点的快照来实现。在INNODB中经过每行记录后保存两个隐藏的列,一个保存行的建立时间,一个保存行的过时(删除)时间,这儿的保存不是时间而是系统版本号,随着事务的数量增长而增长版本号。
SELECT:只找版本号早于当前事务版本的数据,删除版本要大于当前版本号。
INSERT:插入时保存当前版本号为行版本号。
DELETE:为删除的每行保存当前版本号为行的删除标示。
UPDATE:先为插入的行保存版本号,同时保存当前版本号为行删除标示。数据库
4. INNODB经过MVCC来支持高并发,经过间隙锁来防止幻读。缓存
5. MYISAM支持读取的时候插入(并发插入),支持延迟更新索引键(Delayed Key Write),先写内容最后才更新索引,须要指定DELAY_KEY_WRITE。性能优化
SCHEMA与数据类型优化服务器
1. 避免使用NULL。并发
2. 整数类型中,TINYINT使用8位存储空间,BIGINT为64位,通常作SIMHASH选择64位作特征值应该是基于这个,转成16进制有16位。其中指定的宽度只在命令行中展现时起做用。异步
3. 实数类型中,DECIMAL用于存储精确的小数,好比货币。函数
4. VARCHAR比定长CHAR更省空间,由于它只须要使用必要的空间,可是其须要使用1或者2个额外字节用来记录字符串的长度。可是在update的时候,容易形成碎片。
CHAR是定长的,MYSQL根据定义字符串的长度分配空间,并且其会删除全部末尾空格。好比存”STRING “的时候,末尾的空格会被删除。
VARCHAR(5)和VARCHAR(100)存同一个字符虽然空间开销相同,可是在存的时候会消耗更多内存,还有在使用临时表的时候也会比较糟糕。
5. BLOB和TEXT是为存储很大数据而设计的,分别以二进制和字符方式存储。TEXT是SMALLTEXT的同义词,BLOB也是。
6. ENUM类型存储是很是紧凑,其实际存储为整数。
7. BIT能够在一列中存储一个或多个0/1值,最大长度为64。问题是存进去是二进制,可是展现出来倒是十进制的。
8. 计数器表的优化,对于单表的a+1操做可能受到锁的影响,能够经过建立100行数据,而后随机选取一行写,取的时候使用SUM(a)进行查询。
9. 高效ALTER TABLE,修改表结构涉及到不须要改变数据只要改frm文件的时候,可使用语句ALTER COLUMN来操做。
还有替换frm的高效方法,首先create table like来创建新表,修改新表结构,对旧表数据执行锁定”FLUSH TABLES WITH READ LOCK;”
执行系统命令,mv new.frm a.frm之类,记得备份。
UNLOCK TABLES;
10. 高效载入数据到MyISAM表,能够暂时禁用索引。
ALTER TABLE tab DISABLE KEYS;
ALTER TABLE tab ENABLE KEYS;
可是DISABLE KEYS只对非惟一索引有效。
建立高性能的索引
1. B-Tree索引,其意味着全部的值都是按照顺序存储的,而且每个叶子页到根的距离都相等。
B-Tree对索引列是顺序存储的,因此很适合查找范围数据。
缺点是必须按照索引从最左列开始查找,不然没法使用索引。
2. R-Tree(空间数据索引),MyISAM表支持空间索引,能够用做地理数据存储。
3. 独立的列没法使用索引,独立的列是指索引列为表达式的一部分或者函数的参数。
4. 前缀索引,索引很长的字符列会让索引变大变慢,因此选择一个合适的长度来索引是颇有效率的。
首先须要找出合适长度的前缀,用语句:
select count(*) as cnt,LEFT(city,3) as pref from group by pref order by cnt;
调整其中LEFT函数的值选择最合适的长度。建索引时以下:
ALTER TABLE a ADD KEY(city(7));
还能够考虑后缀索引,好比查找某个域名的全部电子邮件地址,须要把字符串翻转后存储。
5. 多列索引的顺序很是重要,要选择最有效率的列放到最左边。
6. 聚族索引并非一种单独的索引类型,而是一种数据存储的方式。
当表有聚簇索引时,它的数据行实际上存放在索引的叶子页(LEAF PAGE)中,聚簇表示数据行和相邻的键值紧凑地存储在一块儿。
7. 当存在OR条件的时候,会看到此时使用了index_merge类型索引,这个说明表上的索引很糟糕,这个是因为在OR左右两个条件都创建了索引,应该修改索引,或者使用IGNORE INDEX来会略某些索引。
8. 在选择多列索引的时候,一般把选择性更大的放到前面(该条件下统计数量更小的)。
9. 在INNODB中最好使用自增做为主键,而使用UUID等随机的聚簇索引会对I/O密集型应用形成很坏性能,它使得聚簇索引的插入变得彻底随机。
10. 当要查询的字段的值在索引中,就称该索引为覆盖索引。在explain的时候extra显示using index。为了能用到覆盖索引,可使用延迟关联(deferred join)。书上有很巧妙的例子:)。注意的是,INNODB中二级索引的叶子节点都包含了主键的值,因此查询的值包含主键id时,主键id能够不在所建的联合索引中。关于延迟关联还有个经典例子,大偏移翻页的时候。
11. 当索引类型为index时,说明MYSQL使用了索引扫描来作排序。
12. 在5.1或更新版本中,INNODB在服务器端过滤掉行后就释放锁,而早期版本中则须要在事务提交后才释放锁。
13. EXPLAIN中出现Using where表示在存储引擎返回行后再使用where过滤条件。
14. 一个诀窍,一个符合查询条件的多列索引中,有时候条件里没有包含存在的索引列,这时候使用IN来知足最左前缀。好比多列索引中有sex列,可是用户查询时没有选择sex,则使用IN(‘M’,’F’)来知足使用索引的条件。
某一些条件好比age,通常是范围查询,而根据最左前缀碰到范围查询后会终止,因此这类通常放在多列索引的最后面。
而使用开始的IN语句知足最左前缀也不能滥用,3个IN条件,每 个有N个枚举值,则会产生N*N*N中组合,下降效率。
15. 按顺序访问范围数据很快,由于顺序I/O不须要屡次磁盘寻道,不须要额外排序操做。
16. 聚簇索引(Clustered Index),一个索引项直接对应实际数据记录存储页。
索引项和实际数据行的排序彻底同样。
一个表只能有一个聚簇索引。可是该列能包含多个列,就像电话簿使用姓氏和名字同时进行排序。
17. INNODB支持聚簇索引,其中聚簇索引就是表,必需要像MYISAM那样的行存储。聚簇索引的每一个叶子节点都包含了主键值、事务ID、用于事务和MVCC的回滚指针以及全部的剩余列。
InnoDB的二级索引和聚簇索引很不相同。InnoDB二级索引的叶子节点中存储的不是“行指针”,而是主键值,并以此做为指向行的“指针”。
在INNODB主键中插入UUID,因为主键会保持有序,会严重影响性能。
查询性能优化
1. 检查响应时间,扫描的行和返回的行,扫描的行数和访问类型(Explain的时候)是三个简单衡量查询的指标。
2. 在进行大查询的时候使用分而治之,好比delete大数据的时候使用limit,使用do while分解操做,避免大语句锁住过多数据,占满事务日志,耗尽系统资源,阻塞不少重要查询。
3. 关联查询拆成简单查询而后在应用层聚合数据,可让缓存效率更高,单个查询能够减小锁竞争,自己查询效率也更高,在数据库中作关联查询还可能致使须要重复地访问一部分数据。
4. mysql客户端和服务器之间的通讯协议是半双工,任何一个时刻只能单向发送数据而不能两边同时进行,像是抛绣球。因此mysql一般须要等全部数据都已经发送给客户端后才能释放这条查询锁占用的资源,这时max_allowed_packet很重要。
5. 一个完整查询包含以下过程包括客户端/服务器端通讯->查询缓存->语法解析器和预处理->查询优化器->数据和索引的统计信息->查询执行引擎->返回结果给客户端。下面会一次说说每一个步骤。
6. 查询状态,一个链接或者线程,在任什么时候刻都有一个状态。
sleep,线程正在等待客户端发来新请求。
query,线程正在执行查询或者将结果发送给客户端。
locked,该线程正在等待表锁。而存储引擎级别的锁好比innodb的行锁并不会体如今线程状态。
copying to tmp table[on disk],线程正在执行查询而且将结果集都复制到一张临时表,通常是group by或者文件排序等操做。on disk表示正在将一个内存临时表放到磁盘上。
sorting result,线程正在对结果集进行排序。
sending data,线程可能在多个状态间传送数据,或者正在生成结果集或者正在向客户端返回数据。
了解这些状态能够很快了解谁正在掷球。
7. 在查询缓存后,先进行语法解析器和预处理,mysql经过关键字将SQL语句进行解析并生成一颗对应的解析树,进行语法规则验证。当语法树被认为合法了,则由优化器将其转化为执行计划,一条语句可能有不少执行方式并返回相同结果,优化器的做用就是找到这其中最好的执行计划。优化器是基于成原本预测。
8. 在不少数据库中IN等同OR,可是在mysql中,会把IN中的数据先进行排序,而后经过二分查找的方式来肯定列表中的值是否知足条件,这是一个O(log n)的操做。当IN中有大量数据的时候效率会更快。
9. 关联查询,MySQL认为任何一次查询都是一次关联,不只仅是UNION,子查询等均可能是。对于UNION,MYSQL现将一系列查询的单个查询结果放到一个临时表中,再从新读出临时表的数据来完成UNION查询。
MYSQL对任何关联都执行嵌套循环关联操做,即先在一个表中循环取出单条数据,而后嵌套循环到下一个表中寻找匹配的行,依次下去,直到找到全部表中匹配的行为为止。
当在FROM子句中遇到子查询时,先执行子查询并将其结果放到一个临时表中,而后将这个临时表当作一个普通表对待(派生表)。
10. 执行计划,MYSQL生成查询的一颗指令数。可使用EXPLAIN EXTENDED后再使用WARNINGS。
任何多表查询均可以用一棵树来表示,好比四表查询:
而事实上MYSQL老是从一个表开始一直嵌套循环,是一颗左侧深度优先的树。
11. 关联查询优化器,用来决定多个表关联时的顺序。
因为其第二个是从第一个表的结果嵌套循环的,因此第一个表尤其重要,优化器会选择扫描不多的行。
若是有超过N各表的关联,那么须要检查N的阶乘种关联顺序,这是很糟糕的。
12. 排序优化,若是order by子句中全部列来自第一个表,那么在处理第一个表是就会进行文件排序,会显示Using filesort
其他状况,都须要先把关联结果放到一个临时表中,最后再进行文件排序。会显示Using filesort,Using temporary;
13. 关联子查询是一个烂查询。select from IN(select id from where)
由于优化器会改写成select from where exists(select * from where AND a.id=b.id)
因此子句须要主句的id才能查询,这样MYSQL会首先对主句进行全表扫描来找出全部id,而后使用id对子句进行逐个执行子查询。
因此方法一是:select * from a
inner join b USING(id)
where c=1;
还有个方法,GROUP_CONCAT。
14. MYSQL目前不支持松散索引扫描,就是最左缀的一个原则,联合索引无法越过左边的字段。虽然其联合索引所有有序。
15. 在同一个表中进行查询和更新,不能用update set a=(select from),要使用生成表的方式来绕过限制,update tb inner join(select) as b using(id) set tb.a=b.a,这样会关联到一个临时表。
16. HINT查询优化器的提示,
HIGH_PRIORITY和LOW_PRIORITY,优先级设置。HIGH通常用于select语句,会将其放到队列的最前面。LOW会让语句一直处于等待状态,只要队列中还有须要访问同一个表的语句。这两个提示只在表锁的存储引擎中有效。
DELAYED,对insert和replace有效,会将提示当即返回给客户端,并将插入的行数放到缓冲区,而后在空闲时批量写入。会致使LAST_INSERT_ID()失效。
FOR UPDATE和LOCK IN SHARE MODE,主要控制SELECT语句的锁机制,只对实现了行级锁的存储引擎有效。
17. count(*)中的*不是指全部的列,而是会忽略全部的列而直接统计行数。
统计同一个列里不一样颜色的商品语句,select sum(if(color=’blue’, 1, 0)) as blue,sum(if(color=’red’, 1, 0)) as red from items;
其中也能够写成sum(color=’blue’),sum(color=’red’)
或者使用以下语句
select count(color=’blue’ OR NULL) as blue, count(color=’red’ OR NULL) as red from items;
18. 关于大数据偏移的一个经常使用方法是延迟关联,
select from a inner join(select id from limit 100,10) as b using(id);
或者计算出具体位置使用between,
OFFSET会致使MYSQL扫描大量不须要的行并抛弃,避免使用OFFSET,好比计算出主键的id,使用
select from a where id<2131231 order by id desc limit 20;
19. MYSQL老是经过建立并填充临时表的方式来执行UNION查询。
MySQL高级特性
1. 分区表:是一个独立的逻辑表,底层是由多个物理子表组成。索引也是按照分区的字表定义的,没有全局索引。
在建立的时候使用PARTITION BY子句定义每一个分区存放的数据。在执行查询的时候优化器会根据分区定义过滤那些没有咱们须要数据的分区,这样查询就无需扫描全部分区。
CREATE TABLE sales(date DATETIME NOT NULL,…) ENGINE=InnoDB PARTITION BY RANGE(YEAR(date))(
PARTITION p_2010 VALUES LESS THAN (2010),
PARTITION p_2011 VALUES LESS THAN (2011),
PARTITION p_catchall VALUES LESS THAN MAXVALUE);
2. 查询缓存能够更快得返回数据,可是高并发下可能成为整个服务器的资源竞争点,多核服务器上还可能致使服务器僵死。因此不少时候咱们认为应该默认关闭查询缓存。
在判断缓存是否命中的时候,MySQL不会解析格式化查询语句,而是直接使用SQL语句和一些客户端的信息,好比空格,注释等任何的不一样都会致使缓存的不命中。
当语句中存在不肯定数据好比NOW()等函数时都不会被缓存。
当打开查询缓存时,每一个读查询都会先检查是否命中缓存,写入缓存的时候会带来系统消耗,当某个表有变更,则对应表的全部缓存都将设置失效,当查询缓存太大或者碎片太多,都会带来很大系统消耗。
因此使用查询缓存时要当心,不要设置太大内存,并且要在肯定有明确收益的时候才使用查询缓存。
优化服务器设置
操做系统和硬件优化
1. 存储引擎一般把数据和索引都保存在一个大文件中,这意味着RAID(磁盘冗余阵列)存储大量数据一般是最可行的方法。
RAID 0
这是成本最低和性能最高的RAID配置,由于其没有冗余,建议只在不担忧数据丢失的状况下使用。并且其的损坏几率比单块磁盘还要高。
RAID 1
提供不错的读性能,并且在不一样磁盘间冗余数据,因此有很好的冗余性。
RAID 5
经过分布奇偶校验把数据分布到多个磁盘,这样任何一个盘的数据失效,均可以从奇偶校验中重建。可是若是有两块磁盘失效了,则整个卷数据都没法恢复。就每一个存储单元的成本而言,这是最经济的,由于只额外消耗了一块磁盘的存储空间。
RAID 10
他由分片的镜像组成,因此对读和写都有良好的扩展性。
RAID 15
由条带化的RAID5组成。用于存放很是庞大的数据集。
2. vmstat和iostat
复制
1. 复制解决的基本问题是让一台服务器的数据与其余服务器保持同步。
2. MYSQL支持两种复制方式:基于行的复制和基于语句的复制。基于语句的复制也叫逻辑复制,很早就存在。基于行的复制5.1版才加进来。这两种方式都是经过在主库记录二进制日志,在备库重放日志的方式来实现异步的数据复制。这意味着同一时间点备库上的数据可能和主库存在不一致。
3. 复制一般不会增长主库的开销,主要是启用二进制日志带来的开销。
可扩展的MySQL
1. 向上扩展:购买更多性能强悍的硬件。
2. 向外扩展,分三部分:复制,拆分以及数据分片。
3. 复制可分为按功能拆分,好比分为论坛、新闻等。
数据分片,全局数据存储在单点上,而对同功能下的数据增加过多的时候进行分片。好比对用户表进行分片。
4. 生成全局惟一的ID
好比分片后,使用AUTO_INCREMENT来获取惟一ID会有问题。
首先可使用auto_increment_increment和auto_increment_offset两个变量来让MYSQL以指望的值和偏移量增长自增列的值。好比两台服务器,能够配置两台服务器的自增幅度为2,其中一台偏移为1一台为2.因此其中一台老是奇数一台老是偶数。
还能够在一个全局数据库中建立自增来生成惟一数字。
还能从全局节点中请求一批数字,用完再申请。
还可使用分片号和自增的组合来做为惟一ID。
可使用UUID()来生成全局惟一值。由于其值很大且不连续,所以不适合作innodb的主键。这时能够考虑UUID_SHORT(),能生成连续的值,并使用64位代替128位。
5. 经过多实例扩展。
6. 经过集群扩展。
7. 向内扩展,好比对不须要的数据进行归档和清理。
备份与恢复
1. 热备份指备份不须要任何的停机服务。
2. 逻辑备份指导出,物理备份指复制原始文件。
3. 差别备份是对自上次全备份后全部改变的部分而作的备份,增量备份则是字从任何类型的上次备份后全部的修改作的备份。
4. 生成逻辑备份:
mysqldump test t1
select into outfile以符号分割文件格式建立数据的逻辑备份。
5. 文件系统快照。
快照会在/dev目录下建立一个新的逻辑卷,能够像挂载其余设备同样挂载它。
6. 备份脚本化