第15章 MySQL优化(一)
第15章 MySQL优化(一)
一、优化
- 表结构是否合理,范式化?数据类型?varchar(可变长,便于压缩)和char还有text(存储一个指针,执行外部存储的原文)读取记录的时候,考虑到page的大小有限,如果一条记录的大小就占用了好几个page显然是不合理的,所以特别长的文本需要使用text类型,这样读取出来的text部分就是一个指针,性能更好。
- 什么样的索引科学?什么样的存储引擎好?锁、隔离机制?所有的内存用到缓存合适吗?
- 当硬件赶不上业务的时候,该怎么调整服务器性能?
- 能选数字就选数字,数字类型少很多字节,而不是选择字符类型,这样性能会更好
二、索引的建立优缺点
- 提高select性能最好的办法就是在经常查询的列上面建立索引
- 索引条目充当指向表行的指针,允许查询快速确定哪些行符合WHERE子句中的条件,并检索这些行的其他列值。
- 索引尽可能建立在取值为不为空,而且值唯一(或者很少有重复的)列上面
- 并不是索引建立的越多越好,不必要的索引建立会浪费空间和时间来决定用什么索引搜索
- 如果建立了一堆索引,对于数据更新的时候,索引改变需要调整,那么由于大量的索引建立,导致调整b+ tree需要消耗大量的时间(所以需要管理者权衡考虑!)
- 系统会自动在自增的主键建立索引,这样最大的好处就是在
join
操作的时候,可以快速定位到目标 - 当表格比较小的时候,建立索引很浪费,不如全表扫描
- 获取要findall的时候,索引也很浪费,本来就是要把整个表数据读取出来,索引失去意义
二、聚簇索引
聚簇索引:索引的顺序和数据存储的顺序完全一致的索引叫做聚簇索引。InnoDB中,表数据文件本身就是按B+Tree组织的一个索引结构,聚簇索引一般就是按照每张表的主键构造一颗B+树,同时叶子节点中存放的就是整张表的行记录数据,也将聚集索引的叶子节点称为数据页。
为什么快:索引记录的位置和存储的位置在顺序上是一样的,这样找起来就非常快。例如:某个节点有多个子节点,从第一个节点到最后一个节点排出来顺序是依次递增的时候,这样显然在查找一个范围的时候就非常快,可以按照顺序来读取磁盘。反之如果存储的地址顺序是乱的,在查找一个范围的时候就不能一次读取一片区域出来,效率就会变低,要读取多次。
三、复合索引
- 根据多个列建立索引,会有不同列的优先级,比如姓名相同按照年龄排序,年龄相同安装学号排序
- 最多16列,有数量限制
- 建立三个单独的索引比建立一个复合的索引要浪费空间,B+树的叶子节点存储要索引的值还有一个指向硬盘的位置,而建立三个单独的索引,就需要三个树,叶子结点存储的同理,也就是说建立复合索引相对来说更好。而且调整一棵树的速度比调整三棵树的效率显然要快的。
- 所以复合索引的顺序非常的重要!
四、前缀索引
- 假如某些国家的人名非常长,达到了300个字符,在建立索引的时候可以只使用前N个字符
- 这样可以减少IO操作,单条记录的大小,然后增加每个page能够读取到记录的条目数量
五、Hash索引
- 通过Hash算法(常见的Hash算法有直接定址法、平方取中法、折叠法、除数取余法、随机数法),将数据库字段数据转换成定长的Hash值,与这条数据的行指针一并存入Hash表的对应位置;如果发生Hash碰撞(两个不同关键字的Hash值相同)可以通过reHash一下,全部重新打乱,增加Hash值的长度,或者通过链表的方式往后面增加
- hash索引时候单值的查找
六、Row format
- REDUNDANT:有冗余,假如varchar(100),实际写入20个字符,实际存储的时候占用100个字符(前缀索引长度可以达到767)
- COMPACT:紧凑的,假如varchar(100),实际写入20个字符,实际存储的时候占用20个字符(前缀索引长度可以达到767)
- DYNAMIC:动态的,假如varchar(100),实际写入20个字符,20个字符都是完全一样的,实际存储的时候不压缩(前缀索引长度可以达到3072)
- COMPRESSED:压缩的,假如varchar(100),实际写入20个字符,20个字符都是完全一样的,实际存储的时候会压缩一下(前缀索引长度可以达到3072)
- 有些时候不压缩反而比较好,因为每个record都是长度一样的时候,反而可能比较利于查找。所以一般来说要有所权衡。
七、全文索引
- 参考elasticsearch那一章节
八、不常用的数据处理
- 如果一个表格里面的,很多查询对于这个表都不包含一些列,怎么办?
- 考虑切开这个表,然后使用join连接,拆两个表,常用的放一个,不常用的放一个
- 数据库的block按照列存储,好处就是统计一列的总和,可能效率非常高,缺点是多次插入一个行的时候非常不适合。
九、blob优化
- 是一个二进制数组
- 不存储在表格里面,通过指针关联
- 如果要判断两个blob相等,没有必要把两个特别大的blob读取出来,可以通过计算hash值,如果hash不等数值,那肯定不相等
十、table_open_cache
- 数值越大,可以同时打开的表格的数量就越多,这个cache存储的是打开文件的文件标识符
- 假如有三个数据库连接,三个连接同时都在操作tableA,那么缓存中就会有三个这样的表,而不是一个表
- 如果有200个并发的连接,table_open_cache的值应该设置为:200 * N,N就是执行查询的时候join表的最大数量
- 这个值并不是越大越好,服务器内存有限,此外到底能同时打开多少个表,还受到操作系统的限制(文件标识符受到限制)
- 缓存满了怎么办?最近最少使用的时候,就会把这个文件描述符关掉,flush之后再加载其他表进来,也会触发落硬盘的操作!
问题:查看mysql的时候发现系统打开的表格数量好几百为什么呢?
- 一个是因为系统表,有些执行操作的时候,需要用到系统表,所以打开了。
- 假如有三个数据库连接,三个连接同时都在操作tableA,那么缓存中就会有三个这样的表,而不是一个表,这样也会增加一些open table数量
- 一些sql语句执行的时候,系统在优化之后执行可能会创建一些view或者临时表,因此就会发现打开的表数量很大
十一、innodb_page_size
- 数据库默认按照行存储的,如果存满了一个1page就把这一页load到内存里面
- 行的尺寸根页的大小相关,每行的数据的大小应该是innodb_page_size的一半而且必须要小一点,因为有一些元数据在里面,需要占用空间
- 这就是mysql存储行的最大上限