个人的一些注意项总结,书里是5.5,和5.6还是有一些不同点。

ps:索引的地方需要注意,虽然是一个个explain测试过的,但是和网上的言论和书里面介绍的不太一样,真正用的时候还是要多测试。

一、架构历史

1、读写锁(共享锁和排它锁);
2、锁粒度:表锁,行级锁。粒度越小锁开销越大;
3、事务:InnoDB支持,myISAM不支持(也不支持行级锁)
不能空谈事务,首要满足的是ACID测试(原子性、一致性、隔离性、持久性),一个良好的事务处理系统,需要具备这些标准特征,不过在应用逻辑中实现这些非常困难
原子性:事务不可分隔,一致回滚,一致提交
一致性:数据库总是从一个一致性状态转换到另一个一致性状态
隔离性:通常来说,一个事务所做的修改,在最终提交前都是对其他事务隔离的
持久性:一旦提交,永久保存
4、隔离级别:
未提交读(脏读,未提交也可读),一般很少使用;
提交读(不可重复读),一个事务内的2次查询结果可能不一致(倾向于行内数据的修改)。大部分的数据库使用
可重复读:mysql默认,但是还会有幻读的问题(另一个事务删除或新增相关数据,本事务读取的数据还是旧的)
可串行化:最高隔离级别,只有在非常需要一致性而且没有并发的情况,每行数据都会加锁,会造成大量的超时和锁争用问题
5、锁
死锁:相互持有锁
自动提交:修改配置
显式锁:事务中,随时可以执行锁,只有在commit或rollback的时候才会释放
隐式锁:innoDB会根据隔离级别自动加锁
6、各版本并发控制:版本如果有跨度,增加一列保存版本号
7、引擎区别:
InnoDB:支持事务,有行级锁,采用MVCC来支持高并发,热备份(恢复),实现了四个隔离级别
MyISAM:不支持事务,没有行级锁,特定场合性能很好(例如日志表和浏览记录表,不需要处理,开销低、快速插入);不过最主要是崩溃无法恢复,单纯的只读表、数据小的情况下用,回复速度也快。

二、MySql基准测试

1、使用sysbench测试工具
……因为是专门的数据库人员使用的,暂时不看这章了

三、Schema与数据类型优化

1、选择优化的数据类型
①更小的通常更好:使用最小数据类型
②简单就好:使用内建的,eg:使用datatime保存时间而不是varchar
③尽量避免null:需要索引的列如果有null则更复杂,null需要被特殊处理(需要一个额外的字节);其他列优先级不高(有例外:如果数据稀疏,null使用单独的bit存储null,有空间效率)
2、具体类型:mysql支持很多别名,integer,bool,numeric等等,但其实还是基本类型
3、整数类型:tinyint(8位存储空间) smallint(16) mediumint(24) int(32) bigint(64),unsigned(取正数),总体来说是:-2的n-1次到2的(n-1)次-1,eg:int最大是21亿4千7百万;对于存储来说int(1)和int(11)是相同的,它只是为了交互显示,基本没有什么实际意义。
4、实数类型:float,4个字节;double8个字节;浮点运算进行近似计算,使用的是平台的浮点数的具体实现,cpu直接支持,速度快
decimal,精确,财务才用;cpu不支持,mysql服务器自身实现精确计算;计算的时候也是转成double,不过现在最大是65位数字
eg:假如存储财务数据要精确到万分之一分,则可以把金额乘以一百万,以bigint存储,这样可以避免浮点存储的不精确和decimal精确计算代价高的问题。
5、字符串类型
①varchar:它仅使用必要的空间,使用1或2个额外字节记录字符串的长度。utf8是复杂的字符集,所以使用utf8的情况一般使用varchar
②char:定长,一般就是true or false这种使用
③注意:字数越小,分配的内存越小,排序或操作的使用用的内存也小。
④blob和text格式,尽量避免,否则全文检索或排序带着列,临时表可能都会上G。要是必须使用的话,一般会substring截取一些
⑤使用枚举(enum)代替字符串,这是一个优化的途径,就当前的数据量来说用的还是少……和外键类似,不能变并且是按照内部的整数排序的。不过使用enum的话会大大缩小占用空间
6、时间类型:都是精确到秒,不过mysql可以临时运算微秒级别
①datatime:8个字节,无时区关系
②timestapme:4个字节,从1970-1-1到2038年;timestapme可以自动,并且和时区相关,它默认是not null; 一般推荐
7、位数据类型、选择标识符等暂时没有用到过
8、特殊:ip其实是32位无符号整数,不是字符串,小数点只是便于阅读,mysql提供了INET_ATON()和INET_NTOA()函数在这两种表示方法之间转换。
9、陷阱:太多的列。MyISAM的变长行结构和InnoDB的行结构总是需要转换成数据结构,所以常用列和不常用的最好分开

四、范式和反范式

完全的范式和反范式都是实验室里面的,范式化的表update比较快,没有冗余数据(同一个数据如果有出入该数据就废了);
反范式化就是写sql语句简单,关联少,系统开销小,空间大。

五、缓存表、汇总表、计数器表

不精确。实时汇总统计是很昂贵的操作,所以不需要精确的浏览记录等使用缓存表,一个小时等生成一个,查询也快。……
这些都是优化的一些

六、索引,索引很复杂,有专门的书讲

1、索引类型
①唯一索引unique,必须唯一且可以为空,组合的话组合的列值必须唯一
②全文索引fulltext,只能用与MyISAM
③主键索引PRIMARY,相当于id,不能空不能重复
④普通索引Normal,没有限制
2、索引方法,一般常说的就是B-TREE索引
eg“:create table user(……, key(one, two, three)); 共有三个索引
可以使用索引: 多索引只能从左到右按顺序使用,必须先用第一个索引,如果跳过第一个索引直接用第二个就不行了
①全值匹配 one = “value” and two = “xx” and three = “xx”
②匹配最左前缀: 直接one = “value” 可以,但是直接 two = “xxx” 就不能用索引了
③匹配列前缀 one like “va%”
④匹配范围值 one > 1 and one <2
⑤精确匹配某一列并范围匹配另外一列 one = “value” and two like “xx%” 范围包括xx%或><;
3、order by也是可以使用索引的
4、限制:
①必须从左至右按顺序使用,不能跳过
②如果其中有了范围查找,再往右边的查询条件就不能用索引了
eg: where one = “value” and like “xx%” and three = “xxx” 这里three虽然是索引,但是没有效果了

七、索引的案例

http://www.cnitblog.com/aliyiyi08/archive/2008/09/09/48878.html 里面详细,这里就是简单记录
EXPLAIN select * from (select * from (select * from town where id > 0) t where t.id > 110106) t1 where t1.id = 110107;
1、EXPLAIN解释:

+—-+————-+————+——-+—————+————-+———+——-+——+————-+ 
 | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | 
 +—-+————-+————+——-+—————+————-+———+——-+——+————-+ 
 | 1 | PRIMARY | | ref | | | 4 | const | 10 | NULL | 
 | 2 | DERIVED | | ALL | NULL | NULL | NULL | NULL | 1623 | Using where | 
 | 3 | DERIVED | town | range | PRIMARY | PRIMARY | 4 | NULL | 1623 | Using where | 
 +—-+————-+————+——-+—————+————-+———+——-+——+————-+


①id:倒叙执行
②select_type:SIMPLE,PRIMARY最外层,主键,UNION等,SUBQUERY子查询,DERIVED派生等等,可以看到id执行顺序对应的是那个语句
③table:关于哪张表
④type:system1条,const常量,几条、eq_reg主键作为关联条件得到x行、ref主键关联条件、range范围、index扫描所有并包含索引,ALL扫描所有(如果第一个查询就是这个那必须优化了)
⑤possible_keys:能用哪些索引,如果是null就要优化索引了
⑥key:真正用上的索引
⑦key_len:索引长度,字段很长就需要截取了
⑧ref:使用哪些列或者一个常数与key一起从表内选择行
⑨rows:需要检查多少行
⑩Extra:包含了详细信息,这里的解释非常多,不好说。

八、哈希索引

特定场合使用性能好,支持的引擎也少,innodb也有自动给常用列添加哈希的功能,可以关闭。
……

九、索引的优点

1、大大减少了服务器需要扫描的数据量
2、可以帮助服务器避免排序和临时表
3、所以un可以将随机I/O变为顺序I/O
4、是不是索引就是最好的?
不一定,如果表小,全文扫描更好。如果表非常大,就需要创建一个元数据表,这个表加索引,另外还可以使用分区技术

十、高性能的索引策略

1、独立的列,始终会能个将索引列单独放在比较符号的一侧,不能是表达式或者函数的参数
2、前缀索引和索引选择性,text、blob,很长的varchar都需要,mysql不允许索引这些列的完整长度
eg:

SELECT 
 COUNT(DISTINCT LEFT (cityname, 1))/COUNT(*) as sel1, 
 COUNT(DISTINCT LEFT (cityname, 2))/COUNT(*) as sel2, 
 COUNT(DISTINCT LEFT (cityname, 3))/COUNT(*) as sel3, 
 COUNT(DISTINCT LEFT (cityname, 4))/COUNT(*) as sel4 
 FROM town 
 +——–+——–+——–+——–+ 
 | sel1 | sel2 | sel3 | sel4 | 
 +——–+——–+——–+——–+ 
 | 0.2826 | 0.9222 | 0.9688 | 0.9746 | 
 +——–+——–+——–+——–+


当截取1个字符的时候选择性是0.28,截取2个字符的时候就大大提升,选择3个的时候提升较少,4个字符的提升就可以忽略不计了。
3、多列索引
①什么时候用多列索引:虽然新版本引入了“索引合并”的策略,但是给每一个条件都加上索引肯定是性能不好的,最好的情况也就是一星索引,和最好的三星索引差着几个数量级。
一般的建议是有多个and、多个or,或者在explain里面看到了索引合并(Extra: Using union(PRIMARY, user_index);)
②多列索引的顺序:最简单是按照排序的列顺序,没有排序和分组的可以考虑将选择性最高的排在前面。因为排序是顺序I/O,认为修改排序的话就造成随机I/O

十、覆盖索引

1、如果一个索引包含(或者说覆盖)所有需要查询的字段的值,我们就称之为“覆盖索引”。
2、好处:减少数据访问量,是顺序I/O,对InnoDB非常有用
3、注意:覆盖索引必须要存储索引列的值,而哈希所以、空间索引和全文索引等都不储存值,所以只能用B-Tree
需要研究一下,东西很多

十一、mysql5.6测试各种情况下是否使用了索引,书是第三版是5.5,其中很多地方挺奇怪,真正使用的时候研究一下

1、主键
① = 直接走
② 范围 between in <> != 都可以用,其他条件是=则走其他索引,无论是不是关联其他表
③范围,其他多个条件包含主键存在=,则走主键的=
④order by 可以用,但是条件包含=,则还是走=
⑤group by 单条件可以,多不可以
2、其他单独列(int)
①=直接走,没有其他主键的=
②between <> 可以,in参数1个可行,多个不行, != 不行。其他有主键的走主键
③order by 不能
④group by 单条件可以,多不可以
⑤多个and走主键索引或唯一索引,都是普通索引则按照左右的顺序,多列索引也是
⑥多个or不行
2、其他单独列(varchar)
①=直接走,没有其他主键的=
②between可以, in单个参数 可以多个不行,<> != 不行。其他有主键的走主键
③like 右%可以
③order by 不能
④group by 单条件可以,多不可以
3、多列索引
①索引从左至右,只有左边可以,只有右边,或者跳列都不行
②group by 同上,只能有一个条件,也就是最左边的索引
③!=哪里用都不行,第一列是范围也不行,between和in同其他
4、join
①LEFT RIGHT 都不行
②inner挺奇怪,用到了不相关的索引……

十二、查询性能优化

1、很慢的原因分析:
①访问了太多的行或是列
②分析了不需要的数据行
③请求了不需要的数据
2、重构
①一个复杂还是多个简单:
现在的mysql是简单查询很快,解析和数据传输比查询慢很多,所以建议是一次查询多个简单的,并且多返回一些数据
②切分查询
例如删除,可以写方法或是函数一次删除10000条,然后等等再继续删除,这是对服务器影响最小的做法
③分解关联查询
多个join拆成3句sql语句,在应用层进行关联,一般感觉很费事,但是它有优势:缓存效率更高,减少锁的竞争,更容易对数据库拆分,查询效率提升,减少冗余记录

十三、查询的基础

1、查询过程:客户 - 缓存 - 解析器 - 解析树 - 预处理 - 解析树 - 查询优化器 - 执行 - 引擎 - api - 数据DB - 返回 - 缓存 - 客户
ps:解析和预处理,有问题就终止查询,不真正走查询
2、通信协议:“半双工”,意味着接收和发送不能是同时的,所以才会有读写分离
3、如何进行关联查询?关联是很广泛的,可能自己单独的select都可能是关联的
无论是join还是子查询都是:将结果放入一张临时表,去下一张表查找,找到就继续找不到就回溯到上一张表,一直如此循环
ps:右外连接会自动改为等价的左外连接
4、无论如何排序都是一个成本很高的操作,所以从性能角度考虑,应尽可能避免排序或者尽可能避免对大量数据进行排序

十四、优化特定类型的查询

1、count(),不统计null,直接用性能更好,*只计算行数。建议不是必须的情况下使用近似值,使用优化器EXPLAIN的估算值或删除一些影响不大的条件
2、子查询尽量用关联查询替代(in用left join替代)
……
看了一下很多的优化网上都有,看了书能确定一下哪些是正确的,网上太杂了。
深度的优化看不太懂,不过那估计就是数据工程师的事情了。

以上就基本的优化和常用的地方,下一次看完了后面的章节,写一写数据备份、游标、缓存、分布式等方面需要注意的点。