首页 > 技术文章 > MySQL 第八天(核心优化二)

Prozhu 2016-11-18 17:05 原文

一.昨天内容回顾

  1. 存储引擎

    保存数据的格式(技术),不同格式体现特性不一样

    myisam

    ① 结构、数据、索引 文件单独存储

    ② 存入数据顺序(不考虑主键顺序) ,写入数据速度快

    ③ 并发性,低,锁整张表

    ④ 压缩机制

    innodb

    结构有单独文件,数据索引合并到一个文件中

    (通过设置,可以给每个表设置一个"数据/索引"文件)

    ② 存入数据顺序(给考虑主键值的先后顺序,数值大小排序存储)

    ③ 并发性,高,锁行

  2. 字段选择

    ① 字段选取占据空间小的(bigint int mediumint smallint tinyint)

    ② 内容长度固定,选取char类型使用 varchar()

    ③ 数据最好存储为整型的(时间set/enum、ip地址)

  3. 逆范式

     

  4. 索引

    索引是数据结构,其内部有算法(规律、规则)

    1. 四种类型、创建、删除

    四种:主键、唯一[例如用户名唯一]、普通、全文索引 ,复合索引

    1. 执行计划

    针对查询select语句起作用

    sql语句在没有执行之前把所有需要的资源都准备好,我们可以预先 查看下

    我们关心sql语句是否用到索引

    explain sql语句\G;

    1. 适合场合

    ① where

    ② 排序字段

    select * from 表名 order by 字段 limit 1000000,50; 不会用索引

    select * from 表名 order by 字段 limit 50; 用索引

    select * from 表名 order by 字段 limit 100,50; 用索引

    select * from 表名 order by 字段 limit 偏移量,50; 用索引

    偏移量如果超过10万,就不会使用索引。

    ③ 索引覆盖

    ④ 连表查询,外键设置索引

    1. 使用原则

    ① 字段独立

    ② 左原则(模糊查询)

    ③ 复合索引

    ④ or原则

  5. 索引

    1. 设计依据

    ① 被频繁使用的字段设置索引

    字段被频繁用在whereorder等条件里边。

    数据表创建完毕,要预估那些字段被经常使用,就给其创建索引

    ② 执行时间长的sql语句考虑设计索引

    可以利用"慢查询日志"收集这样的sql语句并优化设计索引

    ③ 逻辑非常重要的sql语句考虑设计索引

    例如商城系统里边,会员给自己账户充值就比较重要

    还有会员下订单购物,进行付款的时候也比较重要。

     

    ④ 字段内容足够花样化,可以考虑设计索引

    反面教材,性别不能设计索引(内容的取值非常少)

    2. 前缀索引

    什么是前缀索引:

    如果一个字段的内容的前边的n位信息已经足够可以标识当前的字段内容,就可以把字段的前n位获得出来并创建索引,

    通过字段内容前n位创建的索引就称为"前缀索引"。

     

    例如:

    纪无

    云斐

     

     

    以上字段内容,通过前1位,就可以唯一标识当前字段内容,这样就把前1位取出来创建索引

    好处:索引占据的物理空间要比较小,这样的索引运行速度快、效率高,对mysql整体性能提升有很大帮助。

     

    具体操作:

    alter table 表名 add key (字段(位数))

     

    思考:

        到底是前几位可以标识当前字段内容

        通过substring获得字段的前n为信息,从1开始递增时获取

        获取的时候去除重复的,计算总个数,不断增加n的数值,直至总个数稳定

        此时n的数值就是适合做"前缀索引"的数字。

     

        索引是给sql语句做优化

        前缀索引,是给索引做的优化

     

        获得字段的前n位:substring(字段,开始位置,长度n) mysql函数

    同上上图可以知道,通过前11位,可以给epassword字段设置索引。

     

     

    3. in条件索引使用

    4. 全文索引

    什么是全文索引:

    其他索引是把字段的内容作为一个整体进行索引设计

    全文索引,类似我们有一篇作文,把作文中的一些关键字给获取出来当成是索引内容。

    具体理解,就是做like模糊查询,类似baidu搜索一些关键字效果。

     

     

     

     

     

    全文索引注意:

    ① 字段类型必须为varchar/char/text类型

    ② mysql 5.6.4之前只有Myisam支持,5.6.4之后则Myisaminnodb都支持。

    ③ mysql中的全文索引目前只支持英文(不支持中文),如果需要支持中文可以使用sphinx

    ④ 现实生产中mysql的全文索引不经常使用,sphinx常使用

    mysql全文索引自作聪明,对关键字的收录有自己的考虑。

     

    版本是5.5.27,因此只有Myisam支持全文索引。

     

     

    4.1 具体操作

    CREATE TABLE articles (

    id INT UNSIGNED AUTO_INCREMENT NOT NULL PRIMARY KEY,

    title VARCHAR(200),

    body TEXT

    )engine=myisam charset utf8;

     

    INSERT INTO articles (title,body) VALUES

    ('MySQL Tutorial','DBMS stands for DataBase ...'),

    ('How To Use MySQL Well','After you went through a ...'),

    ('Optimizing MySQL','In this tutorial we will show ...'),

    ('1001 MySQL Tricks','1. Never run mysqld as root. 2. ...'),

    ('MySQL vs. YourSQL','In the following database comparison ...'),

    ('MySQL Security','When configured properly, MySQL ...');

     

    alter table articles add fulltext index `index_body` (body);

     

    现在已经有了一个index_body的全文索引:

    因此类似如下sql语句就可以使用到索引了

    select * from articles where body like '%内容%';

    但是sql语句需要变形为:

    select * from articles where match(字段body) against(内容);

     

    4.2 复合全文索引

    alter table articles add fulltext index `index_fu` (title,body);

     

    select * from articles where title like '%内容%' and body like '%内容%'

     

    5. 索引结构(了解)

    索引的数据结构

    主要讨论两种:Myisam 和 Innodb

    Mysql的数据结构都是B+tree结构

     

    数据结构:数据以一种规律的、规则的方式组织在一个格式里边,可以保证我们获得数据的快速性。

    5.1 Myisam索引结构

    该Myisam索引结构称为"非聚合型"

     

    上图说明,主键内容在该索引里边通过算法开始被查询、获得,并借助"指针"向下级寻找,直到找到对应的叶子节点。

    叶子节点里边有该关键字对应的记录的物理地址,进而获得对应的记录信息。

     

    索引运行原理:快速定位主键id值,获得对应记录物理地址,获得记录信息。

     

    每个主键id值都是一个节点,节点本身有指针。

    最底层的节点称为"叶子节点",该节点与记录的物理地址直接联系

    上图节点从上到下的层次数是索引结构的高度

    每层节点的数目称为结构的宽度

    结构的宽度、高度的数目由mysql底层算法计算获得(过高、过宽都不利于数据的快速获取)

     

    Myisam其他索引结构与主键索引结构一致。

     

    通过上图索引结构,我们看到了 索引部分 和 数据部分是分离的,它们之间通过物理地址进行联系。

     

    5.2 Innodb索引结构

     

    该Innodb索引结构称为"聚合型"

    聚合在:"索引"和"数据"是合并在一个文件里边的。

     

    下图表示innodb的其他索引(唯一、普通)

    该(用户名字)其他索引运行原理:

    ① 通过索引结构内部的算法快速定位该名字对应的"叶子节点"

    ② 叶子节点 里边对应的是关键字的记录主键id

    ③ 通过记录主键id值走主键索引即可

     

     

    innodb(主键)索引运行原理:

    ① 通过索引结构快速定位主键id值对应的"叶子节点"

    ② 该叶子节点 里边直接与整条记录信息进行对应(而在Myisam里边,叶子节点与物理地址对应)

     

    innodb索引:

    普通索引关键字----->记录的主键id值------>记录的整条信息

     

    三.缓存设置

    有的被频繁执行的sql语句,比较消耗时间、消耗系统资源(没的优化可做)

    并且每次获得数据还不太发生变化

    那么就把这个sql语句获得信息给缓存起来,供后续执行使用

    这样非常节省系统资源。

    1. 具体使用

     

     

     

     

  6. 缓存失效

    数据表的数据有变化 或者 数据表结构有变化,则缓存失效。

     

    3. 什么情况不使用缓存

    sql语句每次获得数据有变化。

    例如有 时间信息、随机数等

     

    4. 生成多个缓存

    生成缓存的sql语句对"空格"、"大小写"比较敏感

    相同结果的sql语句,由于空格、大小写问题就会分别生成缓存。

     

    5. 不使用缓存

    sql_no_cache 不进行缓存

     

    6. 查看缓存空间使用情况

     

    总结:

  7. 索引依据:频繁、时间长、逻辑重要
  8. 前缀索引
  9. 全文索引(搜索引擎 baidu google 数据检索)
  10. 索引结构:Myisam innodb(主键、其他索引)
  11. 缓存设置

     

    四.分表设计

    一个数据表里边存储的记录信息太多了,记录的条数达到1-2亿条信息。

    这时该数据表的活性就大大降低,数据表的运行速度就比较慢、效率低下,影响mysql数据库的整体性能。

    现在设置一个水平分割,把许多的记录信息分别存储到不同的数据表里边,这样每个表存储的记录就比较少,该表的活性大大提高。

     

    分表设计的两种模式:

    ① 逻辑方式分表

        mysql数据库本身就有分表技术,该方式的分表可以节省php的逻辑处理

     

        

    ② 物理方式分表

        自己手动创建多个数据表出来

        php程序需要考虑分表算法:数据往哪个表,从哪个表

        

     

    1. 演示逻辑分表设计

    mysql本身就支持的分表技术

     

    以上逻辑分表设计,在php程序里边无需设置额外算法代码,还像以往一样直接对goods数据表进行操作即可,mysql本身会考虑分表的算法。

    2. 四种格式的逻辑分表

    具体为:key hash ---->[求余方式]

    range list ---->[范围方式]

     

    注意:分表字段必须是主键 或 主键的一部分

    2.1 key分表

    partition by key(条件字段id) partitions 10;

    2.2 hash分表

    根据表达式/字段方式进行分表设计

    partition by hash(表达式/字段) partitions 数量;

     

     

     

     

     

     

    2.3 range分表

    根据 字段/表达式 是否满足某个范围条件进行分表设计

    partition by range(year(pubdate))(

    partition hou70 values less than (1980),

    partition hou80 values less than (1990),

    partition hou90 values less than (2000),

    partition hou00 values less than (2010)

    )

     

     

    2.4 list分表

    根据 表达式/字段 的内容值是否在某个"列表"中进行分表设计。

    partition by list(month(pubdate))(

    partition spring values in (3,4,5),

    partition summer values in (6,7,8),

    partition autumn values in (9,10,11),

    partition winter values in (12,1,2)

    )

    3. 分表管理

    具体就是对已经存在的分表进行增加减少操作。

     

    增加分表 不会引起数据丢失。

    减少分表 在range/list领域造成数据丢失

    key/hash领域不会造成数据丢失,

             这两个领域在进行减少分表的同时就把全部数据重新整合到存在的表中,

    key/hash两种分表与业务逻辑关联不紧密

     

    增加分表

        求余方式: key/hash

        > alter table 表名 add partitions 数量;

     

        范围方式: range/list

        > alter table 表名 add partition(

    partition 名称 values less than (常量)

    partition 名称 in (n,n,n)

    );

    3.2 删除分表

    求余方式(key/hash):

    >alter table 表名 coalesce partition 12;

    删除分表不会造成数据丢失,每次分表数据都重新整合到存在的分表里边。

    范围方式(range/list):

    >alter table 表名 drop partition 分区名称;

    删除分表会造成数据丢失

    ① key/hash方式不会丢失数据

     

    ② range/list会丢失数据

    给range分表写4条记录:

     

     

    把"hou80"的分区删除,从下图查询结果看对应分表的数据也丢失了。

     

     

    4. 物理分表设计

     

    以上goods的物理分表需要增加php的算法逻辑:

    需要计算记录从哪个表、给哪个表

    4.1 php对物理分表的操作

     

     

    5. 垂直分表

    水平分表:是把一个表的全部记录信息分别存储到不同的分表之中。

    垂直分表:是把一个表的全部字段分别存储到不同的表里边。

     

    有的时候,一个数据表设计好了,里边有许多字段,但是这些字段有的是经常使用的,有的是不常用的。

    例如,一个数据表有20个字段,其中10个字段是常用的,后10个字段是不常用的

    那么在操作常用字段的时候,就不得不给其他不常用的字段也分配一定的资源进行操作。

     

    数据表:

    会员表user_id 登录名 密码 邮箱 手机号码 身高 体重 性别 家庭地址 身份证号码

    以上表,红色是常用的,蓝色的是不常用的

    为了使得常用字段运行速度更快、效率更高,把常用字段给挑选出来,因此数据表做以下设计:

    会员表(主)字段:user_id 登录名 密码 邮箱 手机号码

    会员表(辅)字段:user_id 身高 体重 性别 家庭地址 身份证号码

     

    以上把会员表根据字段是否常用给分为两个表的过程就是垂直分表。

  12. 架构设计

    架构设计也称为集群设计:由多台mysql服务器共同支撑网站的运行,每台服务器分担的工作就比较少,运行速度快、效率高。

     

    mysql数据库在运行的时候一般查询/写入的sql语句比例为:7/1

    并且查询消耗的资源比写入要更多。

    因此可以设计一个"主从模式"的集群,与之前redis的主从模式使用模式一致。

     

    维护备份的集群架构:

     

    主从模式的集群架构:

    六.慢查询日志收集

    我们要把系统里边一些执行速度非常慢的sql语句给收集起来,并做分析优化,使得其执行速度加快。

     

     

     

     

     

     

     

    总结:

  13. 水平分表设计

    分的是数据记录

    1. 逻辑分表

    求余:key/hash 范围:range/list

    创建/增加分表:新建表时、分表创建完毕还可以增加

    删除分表:key/hash不会造成数据丢失

    range/list能造成数据丢失

     

    1. 物理分表

    php代码需要增加算法逻辑

  14. 垂直分表

    分的是表的字段

     

  15. 架构设计

    架构集群有两种方式:

    ① 互为备份

    ② 主从模式[常用]

  16. 慢查询日志收集

     

推荐阅读