- 索引的概念 - 用于提高查找速度的一种数据结构 - 为什么要用B+树,B-树和B+树区别,为什么不用红黑树 - Hash表结构存储数据 - 通过key的hash计算得到存储下表 - Hash只能进行等值查询,切换速度非常快,但是无法用于范围查询 - 二叉查找树 - 左边小,右边大,自身带排序 - 二分查找 - 极端情况 - 根节点的选取,如果选取不好就会不平衡 - 出现某一个方向子树过长 - 平衡二叉树 - 改善二叉树极端情况 - 降低IO次数,每走一个节点进行一次IO - 数的高度过高,IO性能下降 - B树 - 存放指针及数据,保存了排序功能 - 指定阶数M,一个节点包含的子节点最大数量M越大,高度越低 - 范围查询大的时候需要返回根节点再次便利 - 存储了data信息,记录增多的时候树的高度会变高 - B+树 - 数据全部存在子节点中,非子节点只存储键值和指针 - 子节点之间添加链表结构,解决范围查询时需要返回根节点 - 范围查询效率提高很多,单个查询比B+树提高不大 - 那些情况适合建立索引,那些不适合建立索引 - 频繁使用where - 分组字段,分组的前提为排序 - 统计字段 - 加了索引不需要产生中间表去重 - 频繁更新字段 - 数据单一固定 - 数据量大(数据类型text) - where条件不怎么用的 - 索引分类,最左前缀,聚簇索引 - 主键索引 - 唯一索引(一级索引) - 普通索引(二级索引) - 联合索引(需要符合最左前缀原则) - 最左前缀 - 第一个值为从小到大排序,第二个不是 - 第一个值确定的情况下,第二个值是有序的 - 从最左边开始连续的索引都可以匹配上,直到遇到范围查询,> < between - 已经排序好的字段是会生效的, - a=1 and b>1 ab都会生效 - a>1 and b=1 b索引会失效,a>1 时b为无序的 - MyISAM和InnoDB数据结构 - MYD数据 MYI索引 - ibd数据和索引,读一个文件速度更快 - 聚簇索引 - 根据主键索引可以直接拿到数据,索引和数据放在一起 - InnoDB - 定义主键为聚簇索引 - 未定义索引,选择第一个部位null唯一索引 - 以上都没用,使用一个6字节长整型的隐式字段ROWID字段构建聚簇索引,该RPWID字段会在插入新行时自动递增 - 非聚簇索引(辅助索引) - 除聚簇索引外 - 只存储主键ID - 查询可能需要回表,通过辅助索引查询得到ID去主键索引中查找 - MyISAM中通过主键查询得到数据在硬盘中的地址,再根据该地址去磁盘中寻找 - 主键索引唯一,辅助索引可能等值也会查询出多个数据 - 索引覆盖 - 通过辅助索引可以获得全部数据,不需要回表 - 索引失效 - select * - %左边 - 未最左匹配 - 数据库认为不要 - 计算 - or - != > < - 优化 - 辅助索引覆盖 - 自增主键ID - 避免select * - 少用子查询,能使用外连接就外连接,避免笛卡尔积 - 使用短索引,非叶子节点存储更多索引降低树的高度 - 为什么推荐使用自增主键作为索引 - 页分裂 - 降低复杂度 - List集合 - 结合源码,回答核心流程,夹带关键字 - ArrayList - 如何扩容,大小如何自动增加 - 1. 初始化,未给定长度,默认调用午餐构造器 - elementdata 常量数组为空 - new之后数组长度为0 - 2. 添加第一个元素 - 计算容量,比较长度后返回初始化长度为10 - 3. 数组扩容 - grow方法增加长度 - 新容量为老容量加上老容量右移以为,即1.5倍 - 掉用复制数组的方法 - 复制某个ArrayList到另一个里面去 - clong,addAll,copy,stream流 - 重写Clone方法 - 浅复制 - 返回一个一样的ArrayList,其中一个改变了元素,另一个也会改变 - 两个集合中存储同一份元素引用 - 深复制 - 重写clone方法,使用迭代器便利,重新创建引用对象,逐个添加 - 索引中ArrayList增加或删除某个元素的运行过程,效率很低吗 - 效率很低,添加或删除某个元素都需要对数组中的元素进行移位,需要不断进行ArrayCopy很浪费时间 - 添加,后面元素都后移一位,再添加 - 删除,后面元素都前移一位覆盖 - 很大的数组需要拷贝,如何快速拷贝 - 创建时就指定数组的大小 - 获得线程安全的ArrayList - synchorizoned关键字 - LinkedList和ArrayList如何选择 - ArrayList底层为数组,查询效率高,增删效率低 - LinkedList底层为链表,查询效率低,增删效率高 - Vector - 扩容为2倍,线程安全 - Set - HashSet - 无序,去重,非线程安全 - new新建HashMap - 底层通过HashMap的key值实现的,值为常量PRESENT(一个空的Object对象) - put调用setValue方法 - 添加时为什么要给个value为PRESENT常量 - PRESENT决定返回oldValue还是null判断是否已经存在 - HashSet remove方法比较PRESENT - HashMap的删除方法成功会返回value,失败返回null,通过返回判断是否删除 - 去重原理 - hashcode和equals方法 - 先判断hash值,再通过==和wquals判断,返回true则为重复元素 - HashSet和TreeSet - 无序HashSet,有序TreeSet - 如何得到一个线程安全的Set集合 - Collections.synchorizeonedSet() - HashMap的底层结构 - jdk1.7 数组+单向链表 - jdk1.8 数组+链表(单向/双向)+红黑树 - 内部定义静态Node类 - Node - TreeNode有TreeNode left,TreeNode right继承LinkedHashMap.Entry继承HashMap.Node - 如何解决Hash碰撞 - 存放元素需要通过Hash计算来得到Hash值,Hash值为元素要存放的位置,当两个不同元素经过Hash计算得到的Hash值相同,两个元素要存放在同一个位置,产生冲突 - HashMap的put方法 - 初始化table数组长度为16,第一次添加table为null,通过resize()方法,给新容量16,阈值16*0.75 - threadhold,扩容因子0.75 - 何时从单链表转化为红黑树 - 常量TREEIFY_THREADHOLD = 8 通过treeify()方法重组为红黑二叉树 - 扩容方法 - 通过resize方法扩容,判断是否达到阈值,达到就扩容为原来的两倍 - 数组长度小于临界值MIN_TREEIFY_64或等于null时 - 何时扩容 - 转红黑树时要判断,转换时需要搬运元素,第一个元素要扩容 - 添加一个元素后 - HashMap设置长度为11,那么数组容量为多少 - tbaleSizeFor()方法重组 - hash计算更加平均,与数组长度值有关 - 设置为大于我们自定义的值的第一个2的幂次方的值,设置为11长度为16 - HashMap何时从红黑树转化为单链表模式 - 扩容时需要搬运数据,如果红黑二叉树不需要转化条件就会转化为链表 - resize()方法转移红黑二叉树时会调用splite()方法 - lohead,hihead,分割时会产生高位树和低位树,小于等于6时调用untreeify方法退回链表结构 - 多线程并发使用时,容易造成死循环/死锁 - 非线程安全 - jdk1.7头插法,jdk1.8尾插法 - ConcurrentHashMap - 线程安全的集合 - ConcurrentHashMap在jdk1.7和1.8的区别 - jdk1.7 Segment段数组+Entry数组+单链表 - Segment继承ReenTrantLock类,每一个segment相当于一个锁,这就是分段锁 - 当其它线程进行put操作时,发现锁资源被占用时回去进行节点创建避免线程空闲,这种思想也叫**预创建** - segment长度固定为16,HashEntry可以扩容 - jdk1.8 和HashMap结构一样 - CAS + setCtl - 如何保证线程安全 - key和value不支持null的原因 - 二义性