索引就是一个排列好的数据结构
1.为什么要使用索引1.使用索引可以大大提升查询性能,增加用户体验感。但是回降低增删改性能。
2.查询是互联网开发最频繁的功能
3.创建索引是需要消耗一定的时间的,但是相对于索引对查询性能的提升,这个开销量是值得的
不同的存储引擎,索引存放的位置也不一样
1.InnDB:索引和数据是存放在一个文件中的【聚合(簇)索引】
位置:MySQL57Data数据库名表名.idb【index + database】 —
如果是默认安装的,则在 C:ProgramDataMySQLdata。。。。
2.MyISAM:索引和文件存放在两个文件中【非聚合索引】
数据文件:表名:MYD
索引文件:表名:MYI
1.主键索引
主键索引。表一旦创建了主键,就会自己创建索引
2.普通索引
给普通的列创建索引
create index inx_name on employee(name);
3.唯一索引
给唯一的列创建索引,性能要高于普通索引
create unique index inx_name on employee(name);
4.联合索引
给主键以外多个普通的列创建索引
create unique index inx_name on employee(name,age,birth);
B+树的特征:
1.非叶子节点只能存储索引的key+下一个节点的指针
2.叶子节点存储所有的key+value
3.非叶子节点冗余叶子节点的key
4.叶子节点从小到大排列
5.叶子节点自带指针,这样会提升访问速度
因为B+树的非叶子只存储索引的key和指向下一层key的指针,总共大小约14B,所以第一层就可以存储1170个索引数据,第二层就存储1170*1170,假使就使用3层来存储数据,那么第三层就需要存储索引的key和value【1032b】,使用三层就可以存储2000W+的数据。
互联网和数据库的存储引擎都是InnoDB
一.InnoDB1.天生支持行级锁,但是需要手动支持表锁
2.有事务
3.有外键
4.索引:索引和数据存储在一个文件中
主键索引:主键索引是必不可少的。如果没有创建主键索引,MySql会默认使用主键
索引的key就是主键列的值,索引的value就是存储的当前行数据
非主键索引:
索引的key就是当前列的值,索引的value就是存储的主键值
1.天生支持表锁,不支持行锁
2.,没有事务
3.没有外键
4.索引:非聚合索引 数据和索引不存在同一个文件中
如果非主键索引的叶子节点存放的是整条数据的话,会面临两个问题:
占用的磁盘空间太大,每个叶子节点都要存放数据
维护成本过高,对数据修改要修改多个索引,而且可能会让所有树发生自旋
InnoDB也可以不创建主键
在创建非主键索引是也是会创建成功的,但是非主键索引存放的是主键列的值【MySql内部优化器会使用一个
默认的主键来代替,但是默认的主键性能远不如自己创建的】
强烈建议一定要自己创建主键
整形:因为字符串的比较性能不如整形的比较性能【字符串的底层也是需要换成数字来进行比较的】
自增:不一定使用数据库的自增,也可能会使用业务层面的自增【redis,时间戳,uuid】
如果不是自增的,那麽就会造成树的自旋次数比自增次数多,会影响性能
联合索引的key是创建了几个组合索引的几个列的值
联合索引的value是主键列的值
create index idx_name_age_position on employees(name,age,position);
在判断条件是会从联合索引的最左边开始匹配
6.Sql优化 1. Sql优化是为了提升查询的性能 2.如何优化工程结构的优化:数据库,表,列,数据类型等等
基础规范- 表存储引擎必须使用 InnoDB
- 表字符集默认使用 utf8,必要时候使用 utf8mb4
- 通用,无乱码风险,汉字 3 字节,英文 1 字节
- utf8mb4 是 utf8 的超集,有存储 4 字节例如表情符号时,使用它
- 禁止使用存储过程,视图,触发器,Event
- 对数据库性能影响较大,互联网业务,能让站点层和服务层干的事情,不要交到数据库层
- 调试,排错,迁移都比较困难,扩展性较差
- 禁止在数据库中存储大文件,例如照片,可以将大文件存储在对象存储系统(OSS),数据库中存储路径
- 禁止在线上环境做数据库压力测试
- 测试,开发,线上数据库环境必须隔离
- 库名,表名,列名必须用小写,采用下划线分隔 tb_book t_book
- abc,Abc,ABC 都是给自己埋坑
- 库名,表名,列名必须见名知义,长度不要超过 32 字符
- tmp,wushan 谁 TM 知道这些库是干嘛的
- 库备份必须以 bak 为前缀,以日期为后缀
- 从库必须以 -s 为后缀
- 备库必须以 -ss 为后缀
- 单实例表个数必须控制在 2000 个以内
- 单表分表个数必须控制在 1024 个以内
- 表必须有主键,推荐使用 UNSIGNED 整数为主键
- 删除无主键的表,如果是 row 模式的主从架构,从库会挂住
- 禁止使用物理外键,如果要保证完整性,应由应用程式实现
- 外键使得表之间相互耦合,影响 update/delete 等 SQL 性能,有可能造成死锁,高并发情况下容易成为数据库瓶颈
- 建议将大字段,访问频度低的字段拆分到单独的表中存储,分离冷热数据
- 根据业务区分使用 tinyint/int/bigint,分别会占用 1/4/8 字节
- 根据业务区分使用 char/varchar
- 字段长度固定,或者长度近似的业务场景,适合使用 char,能够减少碎片,查询性能高
- 字段长度相差较大,或者更新较少的业务场景,适合使用 varchar,能够减少空间
- 根据业务区分使用 datetime/timestamp
- 前者占用 5 个字节,后者占用 4 个字节,存储年使用 YEAR,存储日期使用 DATE,存储时间使用 datetime
- 必须把字段定义为 NOT NULL 并设默认值“”
- NULL 的列使用索引,索引统计,值都更加复杂,MySQL 更难优化
- NULL 需要更多的存储空间
- NULL 只能采用 IS NULL 或者 IS NOT NULL ,而在 =/!=/in/not in 时有大坑
- 使用 INT UNSIGNED 存储 IPv4 ,不要用 char(15)
- 使用 varchar(20) 存储手机号,不要使用整数
- 牵扯到国家代号,可能出现 +/-/() 等字符,例如 +86
- 手机号不会用来做数学运算
- varchar 可以模糊查询,例如 like‘138%’
- 使用 TINYINT 来代替 ENUM
- ENUM 增加新值要进行 DDL 操作
- 唯一索引使用 uniq_[字段名] 来命名
- 非唯一索引使用 idx_[字段名] 来命名
- 单张表索引数量建议控制在 5 个以内,如果业务需要,表中需要更多的索引,那就大胆去建索引,为了提升性能,索引多几个没关系。(建索引一定要按照公司的发布流程来走)
- 互联网高并发业务,太多索引会影响写性能
- 生成执行计划时,如果索引太多,会降低性能,并可能导致 MySQL 选择不到最优索引
- 异常复杂的查询需求,可以选择 ES 等更为适合的方式存储
- 组合索引字段数不建议超过 5 个
- 如果 5 个字段还不能极大缩小 row 范围,八成是设计有问题
- 不建议在频繁更新的字段上建立索引
- 非必要不要进行 JOIN 查询,如果要进行 JOIN 查询,被 JOIN 的字段必须类型相同,并建立索引
- 踩过因为 JOIN 字段类型不一致,而导致全表扫描的坑么?
- 理解组合索引最左前缀原则,避免重复建设索引,如果建立了(a,b,c),相当于建立了(a), (a,b), (a,b,c)
- 禁止使用 select *,只获取必要字段
- select * 会增加 cpu/io/内存/带宽 的消耗
- 指定字段能有效利用索引覆盖
- 指定字段查询,在表结构变更时,能保证对应用程序无影响
- insert 必须指定字段,禁止使用 insert into T values()
- 指定字段插入,在表结构变更时,能保证对应用程序无影响
- 隐式类型转换会使索引失效,导致全表扫描
- 禁止在 where 条件列使用函数或者表达式
- 导致不能命中索引,全表扫描
- 禁止负向查询以及 % 开头的模糊查询
- 导致不能命中索引,全表扫描
- 禁止大表 JOIN 和子查询
- 同一个字段上的 OR 必须改写问 IN,IN 的值必须少于 50 个
- 应用程序必须捕获 SQL 异常
- 方便定位线上问题
1.已是慢Sql,慢Sql的原因是什么
两种维度来的得知:
-在mysql本地开启慢sql查询及日志分析,也可以通过explian工具来获知慢sql的原因
- 企业中会使用阿里云rds作为数据库服务器,rds提供了慢sql查询功能,通过查询直接得知当前系统发生了哪些慢查询
- 在自测时发现接口性能非常差,使用explain工具来获知慢SQL的原因
2.有可能是慢SQL,慢SQL的原因是什么
当写完一条sql之后可以用explian工具来检验当前十七日是否是慢sql
explian是mysql一个内部优化器 在sql语句前面加上一个explian就可以对当前sql语句进行分析
并可以看到sql经过优化之后的结果
- 查询的类型
- SIMPLE:简单查询
- PRIMARY:主键查询
- SUBQUERY:子查询
- DERIVED:衍生表【查询一张不存在的表,由查询语句得到一张虚拟表】
- 查询优先级
- 值越大,优先级越高
- 值一样,谁在上面,谁先执行
type列直接描述了当前sql的性能——有没有走索引。type列的各值的性能排序:
NULL > system > const > eq_ref > ref > range > index > ALL
- NULL:直接从索引树得到结果
- system:要查询的数据集中只有1条,那么直接拿出来使用即可,是system
- const:主键跟常量去进行等值比较
- eq_ref:在join查询中,被关联表的主键作为关联条件
- ref
- 简单查询: 在简单查询中,使用了非主键索引做等值匹配
- 复杂查询:被关联查询的表使用了非主键索引作为关联条件
- range:使用主键作范围查询【数据量不能太小】
- index:覆盖索引就会出现index
- 覆盖索引:查询的列都是索引列
- ALL:全盘扫描
- 可能使用到的索引列
- 实际使用到的索引列,注意:不一定说可能使用到的索引列一定就是实际使用到的索引列
- 实际使用到的索引计算出来的值
rowskey-len的计算规则
- 可能要查询的行数,注意不是结果的行数
- 这一次查询给到的额外的信息
- 不要使用 IS NULL 或者 IS NOT NULL
- 不要在条件中使用函数
- 不要使用LIKE ‘%xxx’
- 尽量不要使用OR或者IN,【OR或者IN的范围太大】
- 不要使用 !=
- 不要在索引列进行运算
- 不要使用字符串比较不加单引号
-
使用覆盖索引进行查询
-
使用OR或者IN范围太大
- 分批:多线程跑,每条线程跑一批,合并每条线程的结果——CountDownLatch
CountDownLatch
- JUC包下的一个并发库
- 作用,可以让并发提交多个任务到线程池,让每个线程执行任务,任务执行完,CountDownLatch的值-1,如果值是0,则表示所有的任务执行结束了,如果值>0,表示任务还没结束,需要使用await让主线程进行阻塞,那么就可以由主线程去统计线程池中任务的总和。
1.尽量让Sql命中索引
2.尽量使用覆盖索引
3.使用联合索引,一定要遵循最左前缀法则
4.在数据量大的情况下,索引可能会失败,一定要满足小表驱动大表
5.在多表联查的情况下,可以使用一个表进行字段的冗余【让多表联查变成单表查询】
1.原子性(原子性是指事务是一个不可分割的工作单位,事务的操作要么全部成功,要么全部失败)
2.一致性(一个事务中,事务前后的数据完整性必须保持一致)
3.隔离性(多个事务,事务的隔离性是指多个用户并发访问数据库时,一个用户的事务不能被其他用户的事务所干扰
,多个事务之间的数据要相互隔离)
4.持久性(持久性是指一个事务一旦被提交,他将会永久的刻录在磁盘上,对数据库的改变意义就是永久性的,接下来就算是数据库发生故障也不会对其有任何影响)
1.脏读:A事务读到了B事务尚未提交的数据 -----事务如果未提交不应该会被读到
2.不可重复读:一个事务两次读取的内容不一样 -----一个事务多次读取的的数据应该是一致的
3.幻读:一个事物两次读取的数据量不一致 ------在一个事务中 多次读取的数据量应该是一致的
读未提交:读取尚未提交的数据:解决不了任何问题
读已提交:可以解决脏读
重复读取:可以解决脏读和不可重复读
串行化:相当于锁表 可以解决脏读 幻读 不可重复读



