目录
数据库事务
数据库事务的四大特性
原子性:要么都做,要么都不做。
一致性:转账为例。用户A和B两者的钱总共是2000,那么他们两个之间无论怎么转账,最后总金额都是2000。
隔离性:多个事务并发执行时,互不影响
持久性:事务一旦提交对数据库的修改永久保存
事务的隔离级别
- 未提交读:就是一个事务可以读取另一个未提交事务的数据。会造成脏读。
- 提交读:就是一个事务要等另一个事务提交后才能读取数据。可以解决脏读问题,但会造成不可重复读。
- 可重复读:在同一个事务里面先后执行一个查询语句的时候,得到的结果是一样的。会有幻读现象。
- 可串行化:事务在执行的时候不允许别的事务并发执行。完全串行化的读,每次都要获得表级共享锁,读写相互都会堵塞。
事务各隔离级别下的并发问题
事务并发访问引起的问题及如何避免:
1、更新丢失:事务A在对数据进行更新操作,事务B也在对同一数据更新操作并完成了提交,然后事务A遇到异常进行回滚导致事务B的更新丢失。
解决办法: MySQL所有事务隔离级别均可避免。
2、脏读:一个事务读到另一个事务未提交的数据。
解决办法: 提交读(READ-COMMITTED)可以避免。
3、不可重复读:事务A多次读取数据,事务B在事务A读取的过程中对数据做了更新并提交,导致事务A多次读取数据的结果不一致。(侧重于对同一数据的修改)
解决办法:可重复读(REPEATABLE READ)可以避免。
4、幻读:事务A读取若干行数据,事务B以插入或删除行的方式,修改了事务A的结果集。(侧重于新增或删除)
解决办法:可串行化(SERIALIZABLE)可以避免。
数据库的锁
1.数据库锁有哪些
行锁 ,表锁 ,页锁, 乐观锁 ,悲观锁
行锁:开销大,加锁慢;会出现死锁;锁定粒度最小,发生锁冲突的概率最低,并发度最高
表锁:开销小,加锁快;不会出现死锁;锁定粒度大,发生锁冲突的概率最高,并发度最低
开销和加锁时间界于表锁和行锁之间;会出现死锁;锁定粒度界于表锁和行锁之间,并发度一般。
悲观锁:就是考虑问题很悲观,每次去拿数据时都认为别人会修改, 所以每次拿数据的时候都会上锁;
实现:sql语句后边加上for update 例如:select id,name from biao for update
乐观锁:就是考虑问题很乐观,每次去拿数据的时候都认为别人不会修改, 所以不会上锁;假设不会发生并发冲突,只在提交操作时检查是否违反数据完整性。不能解决脏读问题
实现:在表里边加一个vesion 例子:select max(nub) ,version from biao
Update biao set nub=nub+1,version=vsersion+1 where id=id and version =version
索引模块
索引是帮助MySQL高效获取数据的数据结构。
索引的分类
- 主键索引 (PRIMARYKEY)
- 唯一索引 (UNIQUE)
- 普通索引 (INDEX)
- 组合索引 (INDEX)
- 全文索引 (FULLTEXT)
什么时候需要创建索引
- 主键自动建立唯一索引
- 频繁作为查询条件的字段应该创建索引
- 查询中排序的字段创建索引将大大提高排序的速度
- 查询中统计或者分组的字段;
什么时候不需要创建索引
- 频繁更新的字段不适合创建索引,因为每次更新不单单是更新记录,还会更新索引,保存索引文件
- where条件里用不到的字段,不创建索引;
- 表记录太少,不需要创建索引;
- 经常增删改的表;
- 数据重复且分布平均的字段,因此为经常查询的和经常排序的字段建立索引。注意某些数据包含大量重复数据,因此他建立索引就没有太大的效果,例如性别字段,只有男女,不适合建立索引。
索引失效条件
- 在 where 子句中使用!= 或 <> 操作符
- 在 where 子句中使用 or 来连接条件,当连接的字段有字段没有索引时,将导致所有字段的索引失效
- 在 where 子句字段进行 null 值判断,
- 在 where 子句中 like 的模糊匹配以 % 开头
- 在 where 子句中对有索引的字段进行表达式或函数操作
- 如果执行引擎估计使用全表扫描要比使用索引快,则不使用索引
索引优化方式?
- 在经常需要搜索的列上,可以加快搜索的速度;
- 在作为主键的列上,强制该列的唯一性和组织表中数据的排列结构;
- 在经常用在连接的列上,这些列主要是一些外键,可以加快连接的速度;
- 在经常需要根据范围进行搜索的列上创建索引,因为索引已经排序,其指定的范围是连 续的;
- 在经常需要排序的列上创建索引,因为索引已经排序,这样查询可以利用索引的排序, 加快排序查询时间;
- 在经常使用在 WHERE 子句中的列上面创建索引,加快条件的判断速度。
怎么验证 mysql 的索引是否满足需求?
用数据库再带的命令 explain 查看语句中索引是否启动
- type: 主要衡量该检索的性能(all 代表全表扫描,index 代表全索引)
- key: 显示 Mysql 实际决定使用的键(索引),null 代表未走索引。
索引的底层结构是什么?说说各种的特点和缺点?
B 树
- 根节点至少有 2 个孩子,至多有 m 个孩子。
- 除根节点和叶节点外,其他每个节点至少有ceil(m/2)个孩子
- 所有叶子节点都位于同一层
B+树(MySQL)
- 非叶子节点仅用来索引,数据都保存在叶子节点中
- 所有叶子节点均有一个链指针指向下一个叶子结点
B+树适合做索引的缘由:
1. B+树的磁盘读写代价更低(程序运行,往往最耗时的操作就是IO,如果IO的次数越少,那么运行也就越快,代价也就越低,B+树内部结构不存放数据,只存放索引,因此其内部节点比B树更小)
2. B+树的查询效率更加稳定,数据存放在叶子节点中,每次查询都需要从根节点到叶节点的进行查询,时间复杂度为O(logn),比较稳定
3. B+树更有利于对数据库的扫描(因为数据只存放在叶子节点,而且有顺序,所以更好的查询数据范围)
Hash 索引无法范围查询,无法模糊查询,无法排序操作,不支持联合索引最左匹配, 无法避免表扫描。但是等值查询具有极高效率。
聚集还是非聚集指的是B+Tree 的叶结点存储数据还是指针
myisam使用非聚集索引,它的索引和数据是分开的;innodb使用聚集索引,索引和数据存在一个文件
两种常见的数据库引擎
- InnoDB 支持事务,支持行锁(读写锁),适合频繁性修改和新增操作;
- MyISAM 不支持事务,不支持行锁,适合大量查询操作。因为行锁的读写锁只能适用于修改,插入和删除都是表锁。
如果应用程序对查询性能要求较高,就要使用 MyISAM 了。MyISAM 的性能更优,占用的存储空间少
如果应用程序一定要使用事务,毫无疑问你要选择 INNODB 引擎。但要注意, INNODB 的行级锁是有条件的。在 where 条件没有使用主键时,照样会锁全表。
现在一般都是选用 Innodb 了,主要是 MyISAM 的全表锁,读写串行问题,并发效率锁表,效率低,MyISAM 对于读写密集型应用一般是不会去选用的。
联合索引的最左匹配原则的成因
(a,b)当做索引时,如果同时查询where a='' and b='' 或者 where a='' 都会使用这个索引,但是只查where b='' 不会用这个索引。
原则:一直向右匹配直到遇到范围查询。
原因:索引保存是按照联合索引的顺序来,先排a再排b
数据库优化
如何定位并优化慢查询Sql
大致思路:
1、根据慢日志定位慢查询SQL
2、使用explain分析SQL(主要看type、extra)
3、修改SQL或者尽量让SQL去走索引
数据库优化手段
- 创建索引:创建合适的索引,我们就可以现在索引中查询,查询到以后直接找对应的记录。
- 分表 :当一张表的数据比较多或者一张表的某些字段的值比较多并且很少使用时,采用水平分表和垂直分表来优化
- 读写分离:当一台服务器不能满足需求时,采用读写分离的方式进行集群。
- 添加缓存机制:使用redis来进行缓存
数据库优化之分表
分表分为水平(按行)分表和垂直(按列)分表。
根据经验,Mysql表数据一般达到百万级别,查询效率会很低,容易造成表锁,甚至堆积很多连接,直接挂掉;水平分表能够很大程度较少这些压力,这时要按行数据进行分表。
如果一张表中某个字段值非常多,而且只有在很少的情况下会查询。这时候就可以把字段多个单独放到一个表,通过外键关联起来。这时要按列数据进行分表。
数据库优化之读写分离
一台数据库支持的最大并发连接数是有限的,如果用户并发访问太多。一台服务器满足不要要求是就可以集群处理。Mysql的集群处理技术最常用的就是读写分离。
主从同步:把改变数据库数据的操作都往主数据库去写,而其他的数据库从主数据库上同步数据。
读写分离:使用负载均衡来实现写的操作都往主数据去,而读的操作往从服务器去。
数据库优化之缓存
在持久层(dao)和数据库(db)之间添加一个缓存层,如果用户访问的数据已经缓存起来时,在用户访问时直接从缓存中获取,不用访问数据库。而缓存是在操作内存级,访问速度快。
作用:减少数据库服务器压力,减少访问时间。
Java中常用的缓存有:
1、hibernate的二级缓存。该缓存不能完成分布式缓存。
2、可以使用redis(memcahe等)来作为中央缓存。
MySQL limit 分页查询优化(百万级优化)
mysql中int(5)和int(10)的区别是什么?
实际没啥区别。。这个5和10并不是最大5位,最大10位的意思。
好比选择了int(5),并且当你选择了0填充的话。你的数据假设存了123,那么你的显示会是00123,(有些操作mysql的工具看不出来)。
执行查询后这个效果。
当id=2 or 3时候,以0位占位。
当id=4的时候,显然他也是可以存放超过5位的。