mysql聚集索引和二级索引
每张使用 InnoDB 作为存储引擎的表都有一个特殊的索引称为聚集索引,它保存着每一行的数据,通常,聚集索引就是主键索引。为了得到更高效的查询、插入以及其他的数据库操作的性能,你必须理解 InnoDB 引擎是如何使用聚集索引来优化常见的查找和 DML 操作。
如果你的表定义了一个主键,InnoDB 就使用它作为聚集索引。因此,尽可能的为你的表定义一个主键,如果实在没有一个数据列是唯一且非空的可以作为主键列,建议添加一个自动递增列作为主键列。
如果你的表没有定义主键,InnoDB 会选择第一个唯一非空索引来作为聚集索引。
如果你的表既没有主键,又没有合适的唯一索引,InnoDB 内部会生成一个隐式聚集索引 —— GEN_CLUST_INDEX,该索引建立在由 rowid 组成的合成列上。数据行根据 InnoDB 分配的 rowid 排序,rowid 是一个 6 字节的字段,随着数据插入而单调递增。也就是说,数据行根据 rowid 排序实际上是根据插入顺序排序。
通过聚集索引来访问一行数据是非常快的,这是因为所有的行数据和索引在同一页上。如果表特别大,相较于行数据和索引在不同页上存储结构(比如 myisam 引擎),这将大大节省磁盘 I/O 资源。
除了聚集索引外的其他索引类型都属于二级索引。在 InnoDB 中,二级索引中的每个记录都包含该行的主键列,以及二级索引指定的列;聚集索引中,InnoDB 通过主键值来查询数据行。
如果主键过长,二级索引就需要更大的空间,因此,使用短的主键列是很有利的。
对于二级索引,叶子节点并不包含行记录的全部数据。叶子节点除了包含键值以外,每个叶子节点中的索引行中还包含了一个书签 —— 相应行数据的聚集索引键。
如果在一棵高度为 3 的二级索引树中查找数据,那需要对这颗二级索引树遍历3次找到指定聚集索引键。如果聚集索引树的高度同样为 3 ,那么还需要对聚集索引树进行 3 次查找,最终找到一个完整的行数据所在的页,因此一共需要 6 次逻辑 IO 访问以得到最终的一个数据页。
-----------------------
索引是一种用于快速查询行的数据结构,就像一本书的目录就是一个索引
那B+树比起B树有什么优点呢?
1. 由于中间节点不存指针,同样大小的磁盘页可以容纳更多的节点元素,树的高度就小。(数据量相同的情况下,B+树比B树更加“矮胖”,就是说从磁盘中查询数据次数更少,更少IO寻址),查找起来就更快。
2. B+树每次查找都必须到叶子节点才能获取数据,而B树不一定,B树可以在非叶子节点上获取数据。因此B+树查找的时间更稳定。
3. B+树的每一个叶子节点都有指向下一个叶子节点的指针,叶子结点之间是类似链表的结构,对于范围批量查询性能很高,方便范围查询和全表查询,顺序扫描性能高:只需要从第一个叶子节点开始顺着指针一直扫描下去即可,而B树则要对树做中序遍历。
聚簇索引
每个存储引擎为InnoDB的表都有一个特殊的索引,叫聚集索引。聚集索引并不是一种单独的索引类型,而是一种数据存储方式。当表有聚集索引的时候,它的数据行实际上存放在叶子页中。一个表不可能有两个地方存放数据,所以一个表只能有一个聚集索引。
因为是存储引擎负责实现索引,因此不是所有的存储引擎都支持聚集索引。InnoDB表中聚集索引的索引列就是主键,所以聚集索引也叫主键索引。
二级索引
在非主键列的其他列上建的索引就是二级索引,级索引可以有0个,1个或者多个
二级索引的节点页和聚集索引一样,只存被索引列的值,而二级索引的叶子页除了索引列值,还存这一列对应的主键值。
二级索引的叶子节点中存储的不是“行指针”,而是主键值,并以此作为指向行的“指针”。
这样的策略减少了当出现行移动或者数据页分裂时二级索引的维护工作。使用主键当做指针会让二级索引占更多空间,但好处是InnoDB在移动行时无需更新二级索引中的这个指针。
聚集索引的优点:
- 可以把相关数据保存在一起,例如实现电子邮箱时,根据用户ID来聚集数据,读取少数的数据页就能获取某个用户的全部邮件。
- 聚集索引将索引和数据保存在同一个B树中,因此从聚集索引中获取数据比在非聚集索引中要快一些。
聚集索引的缺点:
- 插入速度严重依赖插入顺序。按照主键的顺序插入是加载数据到InnoDB表中速度最快的方式。假如磁盘中的某一个已经存满了,但是新增的行要插入到这一页当中,存储引擎就会把该也分裂成两个页面来容纳该行,这就是一次页分裂操作。页分裂会导致表占用更多的磁盘空间。
- 更新聚集索引列的代价很高,会强制InnoDB将每个被更新的行移动到新的位置。
- 用二级索引访问数据需要两个索引查找,不是一次。因为要先从二级索引的叶子节点获得主键值,再根据这主键去聚集索引中查到对应的行,所以需要两次B树查找。
括号题:比如n=3,输出 ()()() 、(())()、((()))、()(())
package waitMe;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Scanner;
/**
* @Auther: zihan.tech
* @Date: 2021-01-31
* @Description: waitMe
* @version: 1.0
*/
public class KuoHao {
public static void main(String args[]){
Scanner sc= new Scanner(System.in);
int n = sc.nextInt();
List<String> result = generateParaenthsis(n);
Iterator i = result.iterator();
while(i.hasNext()){
System.out.println(i.next());
}
}
public static List<String> generateParaenthsis(int n){
List<String> result = new ArrayList<>();
doGenerate(0,0,"",result,n);
return result;
}
public static void doGenerate(int left, int right, String s, List<String> result, int n)
{
if(left == n && right == n){
result.add(s);
return;
}
if(left<n){
doGenerate(left+1,right,s+"(",result,n);
}
if(right<n&&left>right){
doGenerate(left,right+1,s+")",result,n);
}
}
}
jvm
Java内存空间(堆栈)
基本类型的变量和对象的引用变量都是在函数的栈内存中分配
堆内存用来存放由new创建的内存数组
在堆中产生一个数组或对象之后,还可以在栈中定义一个特殊的变量,让栈中的这个变量的取值等于数组或对象在堆内存中的首地址,栈中的这个变量就变成了数组或对象的引用变量,以后就可以在程序中使用栈中的变量来访问堆中的数组或者对象,引用变量就相当于为数组或者对象起的一个名字。
数组和对象在没有引用变量指向它的时候,才变为垃圾,不能再被使用,在随后的一个不确定时间被垃圾回收器收走(释放掉)。
这也是Java比较占内存的原因,实际上,栈中的变量指向堆内存中的变量,这就是Java中的指针。
年轻代,年老代,永久代
年轻代和老年代的划分是为了更好的内存分派及回收。提高效率。
堆是垃圾回收机制的重点区域。我们知道垃圾回收机制有三种,minor gc,major gc 和full gc。针对于堆的就是前两种。年轻代的叫 minor gc,老年代的叫major gc。
数据库三范式
1.无重复列
2.不存在非主属性对主属性的部分函数依赖(学号 课名 姓名 系名 系主任 分数)
3.在2NF基础上消除非主属性对码的传递函数依赖
死锁
A锁了资源1,B锁了资源2
A想要资源2,B想要资源1
预防:资源一次性分配(破坏请求条件),只要有一个资源得不到分配,也不给这个进程分配其他资源(破坏请保持条件)可剥夺资源,当进程获得了部分,得不到其它资源,则释放占有的资源(破坏不可剥夺条件)资源有序分配:系统给资源赋予编号,每一个进程按序号递增请求资源,释放则相反(破坏环路等待条件)
解除死锁:剥夺资源,撤销进程
银行将算法:当进程首次申请资源时,要测试该进程对资源的最大需求量,如果系统现存的资源可以满足它的最大需求量则按当前的申请量分配资源,否则就推迟分配。当进程在执行中继续申请资源时,先测试该进程本次申请的资源数是否超过了该资源所剩余的总量。若超过则拒绝分配资源,若能满足则按当前的申请量分配资源,否则也要推迟分配。
锁机制
由读表操作加上的锁,加锁后其他用户只能获取该表或行的共享锁,不能获取排它锁,也就是说只能读不能写
由写表操作加上的锁,加锁后其他用户不能获取该表或行的任何锁,典型是mysql事务