索引
之所以要建立索引,其实就是为了构建一种数据结构,可以在上面应用一种高效的查询算法,最终提高数据的查询速度。
https://www.cnblogs.com/aspwebchh/p/6652855.html
树索引
术语“聚簇”表示数据行和相邻的键值紧凑地存储在一起,因此这种索引被称为聚簇索引,或聚集索引。这种索引方式,可以提高数据访问的速度,因为索引和数据是保存在同一棵B树之中,从聚簇索引中获取数据通常比在非聚簇索引中要来得快。
聚集索引:一张表只能有一个聚集索引,一般为主键,表会根据聚集索引形成一棵树,这样可以加快检索的速度,但是会增加写入数据的时间,因为每添加一条记录除了将记录写入还要去维持树状结构。
非聚集索引:非聚集索引和聚集索引一样, 同样是采用平衡树作为索引的数据结构。索引树结构中各节点的值来自于表中的索引字段, 假如给user表的name字段加上索引 , 那么索引就是由name字段中的值构成,在数据改变时, DBMS需要一直维护索引结构的正确性。如果给表中多个字段加上索引 , 那么就会出现多个独立的索引结构,每个索引(非聚集索引)互相之间不存在关联。 如下图每次给字段建一个新索引, 字段中的数据就会被复制一份出来, 用于生成索引。 因此, 给表添加索引,会增加表的体积, 占用磁盘存储空间。非聚集索引的叶子节点中也包含了记录的主键,这样的策略减少了当出现行移动或者数据页分裂时辅助索引的维护工作,因此innodb引擎在查询辅助索引的时候会查询两次,首先通过辅助索引得到主键值,然后再查询主索引
非聚集索引和聚集索引的区别在于, 通过聚集索引可以查到需要查找的数据, 而通过非聚集索引可以查到记录对应的主键值 , 再使用主键的值通过聚集索引查找到需要的数据,如下图
https://www.cnblogs.com/xiaoxi/p/6868087.html
https://blog.csdn.net/suifeng3051/article/details/52669644/
b-树索引
树的宽度是指最多结点数的层中包含的结点数,上图中树的宽度m=4,则B树遵循以下几点:
1. 只有一个根节点或者根节点为空
2. 除了根节点,每个节点中包含的key值应该是[ceil(m/2),m-1],比如B中有三个key值,则在[2,3]的范围内
3. 所有的根节点在同一层
4. 一个节点的左子树均小于该节点key值,右子树均大于该节点key值。比如D<3<E<9<F<15<G
b+树索引
B+树与B树的不同点:
1. 一个节点有n个key值,则将分为n叉,即有n个子树。
2. 内部节点只是只是充当索引,仅存储其子树中最大(最小)关键字
3. 叶子节点中包含所有关键字,及指向含这些关键字记录的指针,且叶子节点本身根据关键字自小而大顺序连接
B+树的查找过程,与B树类似,只不过查找时,如果在非叶子节点上的关键字等于给定值,并不终止,而是继续沿着指针直到叶子节点位置。因此在B+树,不管查找成功与否,每次查找都是走了一条从根到叶子节点的路径。
B+ 树的优点在于:
- 由于B+树在内部节点上不包含数据信息,因此在内存页中能够存放更多的key。 数据存放的更加紧密,具有更好的空间局部性。因此访问叶子节点上关联的数据也具有更好的缓存命中率。
- B+树的叶子结点都是相链的,因此对整棵树的便利只需要一次线性遍历叶子结点即可。而且由于数据顺序排列并且相连,所以便于区间查找和搜索。而B树则需要进行每一层的递归遍历。相邻的元素可能在内存中不相邻,所以缓存命中性没有B+树好。
索引的使用:
1. 主键和外键一定要加索引
2. where,on,group by ,order by 中所用到的列加索引
3. like "xxxx%"走索引,"%xxx"不走索引
4. 索引列不能参与计算
5. 区分度高的适合加索引
hash索引
hash索引的结构类似于hashmap, 根据索引的hash值进行存储的,因此只能用于精确查找,并且精确查找的速度很快,但是不能用于范围查找以及排序。
分库分表
https://www.cnblogs.com/daiwei1981/p/9416057.html
分库:面对高并发的读写访问,当数据库master服务器无法承载写操作压力时,通过分库策略可以提高数据库并发访问能力。
分表:解决单表数据量过大,造成检索效率低等问题。
分库分表策略
range分:将连续的数据分在一个表中,例如将一段时间内的数据写在一个表中,用得比较少,因为会产生热点问题。
hash分:对关键字进行hash算法,均匀的分布在各个表上。但是扩容比较麻烦,会有一个数据迁移的过程。
1. 水平/横向切分
解决表太大造成的性能和服务器空间问题,一般是对关键字(比如用户id)取模,实现对数据访问进行路由。
2. 垂直/纵向切分
解决列太多的问题,可以将经常组合查询的列放在同一表中,不太经常访问的列单独成表。
分库分表解决主键问题
https://www.cnblogs.com/daiwei1981/p/9416081.html
可以使用snowflake生成一个uuid, 此uuid是一个64位的long型数,1 bit不使用,41bit用来表示时间,精确到毫秒,10bit用来表示库房和机器,12bit用来表示序列号。
动态扩容
https://baijiahao.baidu.com/s?id=1584744472767329273&wfr=spider&for=pc
将从库升级为主库,更改分片策略,解除主从关系,清除冗余数据。
SQL语句
#建表
CREATE TABLE DataTest(
ID BIGINT NOT NULL IDENTITY(1,1),
NAME VARCHAR(20),
AGE INT,
SEX VARCHAR(4),
PRIMARY KEY(ID)
);
#建索引
create unique index studentIdIndex on StuClass(STUDENT_ID);
#修改表字段
ALTER TABLE DataTest ALTER COLUMN NAME VARCHAR(20) NOT NULL;
#增加表字段
ALTER TABLE DataTest ADD JOB VARCHAR(20);
#增加默认值
ALTER TABLE DataTest ADD DEFAULT(0) FOR AGE;
#删除表字段
ALTER TABLE DataTest DROP COLUMN JOB ;
#插入数据
INSERT INTO StuClass (STUDENT_ID,CLASS_ID,SCORE) VALUES (1,3,45);
#删除数据
DELETE Student where ID = 13;
#查询
1. DISTINCT
distinct语句中select显示的字段只能是distinct指定的字段,其他字段是不可能出现的。DIATINCT必须在开头。
SELECT NAME,DISTINCT AGE FROM Student -》错误
SELECT DISTINCT AGE,NAME FROM Student -》查询name和age组合不一致的记录
2. JOIN
# https://www.cnblogs.com/reaptomorrow-flydream/p/8145610.html
select * from Student inner join StuClass on Student.ID = StuClass.STUDENT_ID
JOIN: INNER JOIN;FULL OUTER JOIN ;LEFT JOIN; RIGHT JOIN
无论哪种JOIN,列都是两张表的并集,行则各不同:INNER/OUTER JOIN: 两张表的交/并集才出现;LEFT/RIGHT JOIN:左/右表中的才出现;
Hibernate
https://www.cnblogs.com/huajiezh/p/6415431.html
https://www.cnblogs.com/huajiezh/p/6415411.html
Hibernate工作原理及为什么要用?
原理:
1.读取并解析配置文件
2.读取并解析映射信息,创建SessionFactory
3.打开Sesssion
4.创建事务Transation
5.持久化操作
6.提交事务
7.关闭Session
8.关闭SesstionFactory
为什么要用:
.对JDBC访问数据库的代码做了封装,大大简化了数据访问层繁琐的重复性代码。
.Hibernate是一个基于JDBC的主流持久化框架,是一个优秀的ORM实现。他很大程度的简化DAO层的编码工作
.hibernate使用Java反射机制,而不是字节码增强程序来实现透明性。
.hibernate的性能非常好,因为它是个轻量级框架。映射的灵活性很出色。它支持各种关系数据库,从一对一到多对多的各种复杂关系。
cglib动态代理与JDK动态代理的区别:
https://blog.csdn.net/heyutao007/article/details/49738887
ASM是一个Java字节码操纵框架,它能被用来动态生成类或者增强既有类的功能。ASM可以直接产生二进制class文件,也可以在类被加载入Java虚拟机之前动态改变类行为。Java class被存储在严格格式定义的.class文件里,这些类文件拥有足够的元数据来解析类中的所有元素:类名称、方法、属性以及 Java 字节码(指令)。ASM从类文件中读入信息后,能够改变类行为,分析类信息,甚至能够根据用户要求生成新类。
sessionFactory:SessionFactory通常是在应用启动时创建好的,应用程序中的代码用它来获得Session对象。作为一个单个的数据存储,它也是 线程安全的,所以多个线程可同时使用同一个SessionFactory。
session:Session代表着Hibernate所做的一小部分工作,它负责维护者同数据库的链接而且 不是线程安全的,也就是说,Hibernate中的Session不能在多个线程间进行共享。
MyBatis
https://www.cnblogs.com/huajiezh/p/6415388.html
配置:
1. 需要一个全局配置文件,在配置文件中指定数据库的驱动,数据库地址,用户名和密码以及映射文件sqlMapConfig.xml(sqlMapConfig.xml中配置mapper.xml的位置)的地址.
Mybatis封装了与数据库的连接操作,只是暴露出一个sqlSessionFactory供开发人员进行操作。
2. 为需要查询的表分别新建映射文件Mapper.xml,并在其中写sql语句。
3. 写dao层的mapper接口,dao层中的方法不能重载,因为这样sql中的id会冲突。
[自动映射时的dao是没有实现方法是,是依靠动态代理来实现的。当使用非自动映射时,daoImpl extends SqlSessionDaoSupport进行实现]
@Service
publicclass StudentDaoImp extends SqlSessionDaoSupport implements StudentDao{
/**
* 我们发现这个类中没有把SqlSessionTemplate作为一个属性,因为我们继承了SqlSessionDaoSupport
*SqlSessionDaoSupport他会提供sqlsession
*/
@Override
public void save(Student student) {
// TODO Auto-generated method stub
this.getSqlSession().insert("com.hys.app.student.dao.StudentDao.save",student);
}
@Override
public Student getStudent(String id) {
// TODO Auto-generated method stub
returnthis.getSqlSession().selectOne("com.hys.app.student.dao.StudentDao.getStudent",id);
}
/**
* 使用SqlSessionDaoSupport必须注意,此处源码1.1.1中有自动注入,1.2中取消了自动注入,需要手工注入,侵入性强
* 也可在spring-mybatis.xml中如下配置,但是这种有多少个dao就要配置到多少个,多个dao就很麻烦。
* <bean id="userDao"class="com.hua.saf.dao.UserDao">
* <propertyname="sqlSessionFactory" ref="sqlSessionFactory"/>
* </bean>
*/
@Resource
public voidsetSqlSessionTemplate(SqlSessionTemplate sqlSessionTemplate){
super.setSqlSessionTemplate(sqlSessionTemplate);
}
}
在Mybatis中,每一个<select>、<insert>、<update>、<delete>标签,都会被解析为一个MappedStatement对象。Dao接口的工作原理是JDK动态代理,Mybatis运行时会使用JDK动态代理为Dao接口生成代理proxy对象,代理对象proxy会拦截接口方法,转而执行MappedStatement所代表的sql,然后将sql执行结果返回。
MYBATIS和HIBERNATE的区别:
1. Mybatis是半自动ORM映射工具,Hibernate是全自动的映射工具,使用Hibernate查询关联对象或者关联集合对象时,可以根据对象关系模型直接获取,所以它是全自动的。而Mybatis在查询关联对象或关联集合对象时,需要手动编写sql来完成,所以,称之为半自动ORM映射工具。