孤尽训练营打卡日记day04--MySQL优化

前言

        数据库在系统中是非常重要的一环,当数据量大的时候,数据库就会有瓶颈,也就是查询变慢,我们需要对数据库进行优化

建表时优化

Schema 和数据类型优化

整数

        TinyInt,SmallInt,MediumInt,Int,BigInt 使用的存储 8,16,24,32,64 位存储空间,使用Unsigned 表示不允许负数,可以使正数的上限提高一倍

实数

  • Float,Double 支持近似的浮点运算
  • Decimal  用于存储精确小数

字符串

  • Varchar 存储变长的字符串。需要 1 或 2 个额外的字节记录字符串的长度
  • char    定长,适合存储固定长度的字符串,如MD5 
  • Blob,Text  为了存储很大的数据而设计的,分别采用二进制和字符的方式

时间类型

  • DateTime  保存大范围的值,占8个字节
  • TimeStamp  推荐,与Unix 时间戳相同,占四个字节

优化点建议

  • 尽量使用对应数据类型。比如,不要用字符串类型保存时间,用整型保存IP
  • 选择更小的数据类型。能用 TinyInt 不用 Int
  • 标识列(如 主键),建议使用整型,不推荐字符串类型,占用空间更多,而且计算速度比整型慢
  • 不推荐 ORM 系统自动生成的Schema ,通常具有不注重数据类型,使用很大的Varchar 类型,索引利用不合理等问题
  • 真实场景混用范式和反范式。冗余高查询效率高,插入更新效率低,冗余低,插入更新效率高,查询效率低
  • 创建完全的独立的汇总表/缓存表,定时生成数据,用于用户耗时时间长的操作,对于精确度要求高的汇总操作,可以采用 历史结果 + 最新记录的结果来达到快速查询的目的
  • 数据迁移,表升级的过程中可以使用影子表的方式,通过修改原表的表名,达到保存历史数据,同时不影响新表使用的目的
  • 不建议列值默认为 null

不建议为null的原因:

  • 不能使用算术比较运算符,如=、<或<>来测试NULL

You cannot use arithmetic comparison operators such as =, <, or <> to test for NULL.

  • COUNT()、MIN()和SUM()等聚合(组)函数忽略空值
  • 使用DISTINCT、GROUP BY或ORDER BY时,所有空值都被视为相等。

官方文档:“NULL columns require additional space in the row to record whether their values are NULL. For MyISAM tables, each NULL column takes one bit extra, rounded up to the nearest byte.”

Mysql难以优化引用可空列查询,它会使索引、索引统计和值更加复杂。可空列需要更多的存储空间(见上面的e文),还需要mysql内部进行特殊处理。可空列被索引后,每条记录都需要一个额外的字节,还能导致MYisam 中固定大小的索引变成可变大小的索引。

You can add an index on a column that can have NULL values if you are using the MyISAM, InnoDB, or MEMORY storage engine. Otherwise, you must declare an indexed column NOT NULL, and you cannot insert NULL into the column.

你可以在包含NULL值的列上添加索引,如果您使用的是MyISAM、InnoDB或内存存储引擎。除此之外,必须声明索引列NOT NULL,并且不能将NULL插入该列。

索引

        索引包含一个或多个列的值。MySQL只能高效的利用索引的最左前缀列

索引的优势:

  • 减少查询扫描的数据量
  • 避免排序和临时表
  • 将随机IO变成顺序IO(顺序IO 的效率高于随机IO)

B+Tree

        使用最多的索引类型,采用B-Tree数据结构来存储数据(每一个叶子节点都包含指向下一个叶子节点的指针,从而方便叶子节点的遍历)。B-Tree索引适用于全键值,键值范围,键前缀查找,支持排序

限制:

  • 如果不是按照索引的最左原则匹配,则无法使用索引
  • 不能跳过索引中的列,如果使用第一列和第三列索引,则只能使用第一列索引
  • 如果查询中有个范围查询,则其右边的所有列都无法使用索引优化查询

hash索引

        只有精确匹配索引所有的列,查询才有效。存储引擎会对所有的索引列计算一个hash码,哈希索引将所有的哈希码存储在索引中,并保存指向每个数据行的指针

 限制

  • 无法用于排序
  • 不支持部分匹配
  • 只支持等值查询,如 = ,in () ,不支持  <> 

优化建议:

  • 注意每种索引的适用范围和适用限制
  • 索引的列如果是表达式的一部分或者是函数的参数,则失效
  • 针对特别长的字符串,可以使用前缀索引,根据索引的选择性选择合适的前缀长度
  • 使用多列索引的时候,可以通过AND 和 OR 语法连接
  • 重复索引没必要 如  A,B  和 A
  • 索引在 where 条件查询 和 group by 语法查询的时候特别有效
  • 将范围查询放在条件查询的最后,防止范围查询导致的右边索引失效(经测试,索引 (int,string)int是个范围,a < 2 and b = "b" ,走的还是全索引)
  • 索引最好不要选用过长的字符串,并且索引列也不宜为null 

查询时优化

查询质量的三个重要指标

  • 响应时间(服务时间,排队时间)
  • 扫描的行
  • 返回的行

查询优化的点

  • 避免查询无关的列,如使用Select * 返回所有的列
  • 避免查询无关的行
  • 切分查询。将一个对服务器压力较大的任务分解到一个较长的时间中,并分多次执行。如要删除一万条数据,可以分10次执行,每次执行完成后暂停一段时间,再继续执行,过程中可以释放服务器资源给其他任务
  • 分解关联查询,将多表关联查询的一次查询,分解成对单表的多次查询。可以减少锁的竞争,查询本身的查询效率也比较高。因为Mysql 的连接和断开都是轻量级操作,不会由于查询拆分多次,造成效率的问题
  • 注意count 的操作只能统计不为null 的列,所以统计总行数使用 count (*)

        count(1)与count(*)得到的结果一致,包含null值。

        count(字段)不计算null值

  • group by 按照标识分组效率高,分组结果不宜出现行分组列之外的列
  • 关联查询延迟关联,可以根据查询条件先缩小各自要查询的范围,再关联
  • limit 分页优化,可以根据索引覆盖扫描,再根据索引列关联自身查询其他列

如:

select 
id,
name,
age
where
student s1
inner join (
select 
id
from 
student
order by 
age 
limit 50,5
) as s2 on s1.id = s2.id
  • Union 查询默认去重,如果不是业务必须,建议使用效率更高的Union All 
  • in 和 exists

        1)、在两个表差不多大的时候,in和 exists 没区别

        2)、在外表比内表大时,如 select  * from a where (select name from b where id = 2)

     a 表大于 b 表,这种用in

        3)、外表比内表小,用 exists

  • not in 和 not exists   ,用not exists   

补充

1、隐式转换

        条件中的字段类型和表结构类型不一致,MySQL 会自动加转换函数,导致索引作为函数中的参数失效 

2、like

        查询前面部分未输入,以% 开头无法命中索引

3、5.7 版本的一个特性

        支持JSON 格式数据,并提供相关内置函数

create table json_test (name JSON );

insert into json_test values ('{"name":"value1", "name2":"value2"}');

select * from json_test where JSON_CONTAINS (name,'$.name1');

4、关注 explain 在性能分析中的使用 

1)select_type

        simple 表示简单的select ,没有union 和子查询

        primary 有子查询,最外面的 select 查询就是 primary 

        union union中的第二个或随后的select 查询,不依赖外部查询的结果

        dependent union union 中的第二个或随后的 select 查询,依赖外部查询结果

2)type 

        system 表仅有一行(=系统表),这是const 连接类型的一个特例

        const  常量查询

        ref 非谓语索引访问,只有普通索引

        eq_ref 使用唯一索引或组件查询

        all 全表查询

        index 根据索引查询全表

        range 范围查询

3)possible_keys

        表中可能存在帮助查询的索引

4)key

        选择使用的索引

5)key_len

        使用索引的长度 ,如果是聚合索引,能根据这个判断走的什么索引,(a,b)  a   a,b

6)rows

        扫描的行数,越大越不好

7)extra 

        Only index 信息从索引中检索出,比扫描表快

        where used 使用 where 限制

        Using filesort 可能存在内存或磁盘排序

        Using temporary 对查询结果排序时使用临时表

如何根据需求创建表

需求

1、乘客通过网站注册登录

2、实名认证通过mork实现

3、铁路部门管理员有如下功能

  • 车次车厢经停站时刻表的增删改查
  • 用户管理:用户增删改查、黑名单管理,为用户分配角色
  • 角色管理:角色增删改查,为角色分配相应的功能
  • 菜单管理:菜单增删改查

4、定时任务:生成火车票

5、普通用户拥有如下功能

  • 修改信息:密码、住址、电话、邮箱
  • 代沟功能:录入其他乘客信息,合并下单支付
  • 余票查询:可以通过车次、出发站、到达站、日期等条件查询
  • 购买车票下单:选择车次,选择乘车人,座位类型后下单
  • 订单支付:第三方支付、支付宝支付、微信支付

6、支付成功后通知用户

分析:

名词:实体、属性

动词:关系

设计数据库的时候要满足范式

  • 第一范式:每列属性不可拆分
  • 第二范式:表中的每行记录的内容都和主键相关,每列和主键相关
  • 第三范式:每列都和主键列直接关系,而不是间接关系

不忘初心,方得始终;初心易得,始终难守。

你可能感兴趣的:(mysql,数据库,database)