见:https://zhuanlan.zhihu.com/p/68255395
#转发和重定向
转发过程:客户浏览器发送http请求----》web服务器接受此请求–》调用内部的一个方法在容器内部完成请求处理和转发动作----》将目标资源发送给客户;在这里,转发的路径必须是同一个web容器下的url,其不能转向到其他的web路径上去,中间传递的是自己的容器内的request。在客户浏览器路径栏显示的仍然是其第一次访问的路径,也就是说客户是感觉不到服务器做了转发的。转发行为是浏览器只做了一次访问请求。
重定向过程:客户浏览器发送http请求----》web服务器接受后发送302状态码响应及对应新的location给客户浏览器–》客户浏览器发现是302响应,则自动再发送一个新的http请求,请求url是新的location地址----》服务器根据此请求寻找资源并发送给客户。在这里location可以重定向到任意URL,既然是浏览器重新发出了请求,则就没有什么request传递的概念了。在客户浏览器路径栏显示的是其重定向的路径,客户可以观察到地址的变化的。重定向行为是浏览器做了至少两次的访问请求的。
重定向,其实是两次request,
第一次,客户端request A,服务器响应,并response回来,告诉浏览器,你应该去B。这个时候IE可以看到地址变了,而且历史的回退按钮也亮了。重定向可以访问自己web应用以外的资源。在重定向的过程中,传输的信息会被丢失。
#有哪些线程池
详细见:https://blog.csdn.net/jiangpingjiangping/article/details/77860236
线程池为线程生命周期开销问题和资源不足问题提供了解决方案。通过对多个任务重用线程,线程创建的开销被分摊到了多个任务上。其好处是,因为在请求到达时线程已经存在,所以无意中也消除了线程创建所带来的延迟。这样,就可以立即为请求服务,使应用程序响应更快。而且,通过适当地调整线程池中的线程数目,也就是当请求的数目超过某个阈值时,就强制其它任何新到的请求一直等待,直到获得一个线程来处理为止,从而可以防止资源不足。
java中的有哪些线程池?
1.newCachedThreadPool创建一个可缓存线程池程
2.newFixedThreadPool 创建一个定长线程池
3.newScheduledThreadPool 创建一个周期性执行任务的线程池
4.newSingleThreadExecutor 创建一个单线程化的线程池
newFixedThreadPool
创建一个指定工作线程数量的线程池。每当提交一个任务就创建一个工作线程,如果工作线程数量达到线程池初始的最大数,则将提交的任务存入到池队列中。
FixedThreadPool是一个典型且优秀的线程池,它具有线程池提高程序效率和节省创建线程时所耗的开销的优点。但是,在线程池空闲时,即线程池中没有可运行任务时,它不会释放工作线程,还会占用一定的系统资源。
newSingleThreadExecutor
创建一个单线程化的Executor,即只创建唯一的工作者线程来执行任务,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。如果这个线程异常结束,会有另一个取代它,保证顺序执行。单工作线程最大的特点是可保证顺序地执行各个任务,并且在任意给定的时间不会有多个线程是活动的。
newScheduleThreadPool
创建一个定长的线程池,而且支持定时的以及周期性的任务执行,支持定时及周期性任务执行。
newCachedThreadPool
创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。
这种类型的线程池特点是:
工作线程的创建数量几乎没有限制(其实也有限制的,数目为Interger. MAX_VALUE), 这样可灵活的往线程池中添加线程。
如果长时间没有往线程池中提交任务,即如果工作线程空闲了指定的时间(默认为1分钟),则该工作线程将自动终止。终止后,如果你又提交了新的任务,则线程池重新创建一个工作线程。
在使用CachedThreadPool时,一定要注意控制任务的数量,否则,由于大量线程同时运行,很有会造成系统瘫痪。
where a= ? group by b= ?
走了几个索引?
如果经常需要同时对两个字段进行AND查询,那么使用两个单独索引不如建立一个复合索引,因为两个单独索引通常数据库只能使用其中一个,而使用复合索引因为索引本身就对应到两个字段上的,效率会有很大提高。
但是,往往都没有说为什么?想知道以下问题:
1、是不是在任何情况下数据库查询一次只会使用到一个索引?
2、如果不是,那么什么情况下只会使用一个索引?
3、那分别是什么造成上面的查询索引使用问题呢?
与其说是“数据库查询只能用到一个索引”,倒不是说是 和全表扫描/只使用一个索引的速度比起来,去分析两个索引二叉树更加耗费时间,所以绝大多数情况下数据库都是是用一个索引。
我们来想象一下当数据库有N个索引并且查询中分别都要用上他们的情况:
查询优化器(用大白话说就是生成执行计划的那个东西)需要进行N次主二叉树查找[这里主二叉树的意思是最外层的索引节点],此处的查找流程大概如下:
查出第一条column1主二叉树等于1的值,然后去第二条column2主二叉树查出foo的值并且当前行的coumn1必须等于1,最后去column主二叉树查找bar的值并且column1必须等于1和column2必须等于foo。
如果这样的流程被查询优化器执行一遍,就算不死也半条命了,查询优化器可等不及把以上计划都执行一遍,贪婪算法(最近邻居算法)可不允许这种情况的发生,所以当遇到以下语句的时候,数据库只要用到第一个筛选列的索引(column1),就会直接去进行表扫描了。select count(1) from table1 where column1 = 1 and column2 = ‘foo’ and
column3 = ‘bar’所以与其说是数据库只支持一条查询语句只使用一个索引,倒不如说N条独立索引同时在一条语句使用的消耗比只使用一个索引还要慢。
所以如上条的情况,最佳推荐是使用index(column1,column2,column3)
这种联合索引,此联合索引可以把b+tree结构的优势发挥得淋漓尽致:
一条主二叉树(column=1),查询到column=1节点后基于当前节点进行二级二叉树column2=foo的查询,在二级二叉树查询到column2=foo后,去三级二叉树column3=bar查找。
mysql的执行顺序
见:https://blog.csdn.net/u014044812/article/details/51004754
1、SELECT语句定义
一个完成的SELECT语句包含可选的几个子句。SELECT语句的定义如下:
SQL代码
<SELECT clause> [<FROM clause>] [<WHERE clause>] [<GROUP BY clause>] [<HAVING clause>] [<ORDER BY clause>] [<LIMIT clause>]
SELECT子句是必选的,其它子句如WHERE子句、GROUP BY子句等是可选的。
一个SELECT语句中,子句的顺序是固定的。例如GROUP BY子句不会位于WHERE子句的前面。
2、SELECT语句执行顺序
SELECT语句中子句的执行顺序与SELECT语句中子句的输入顺序是不一样的,所以并不是从SELECT子句开始执行的,而是按照下面的顺序执行:
开始->FROM子句->WHERE子句->GROUP BY子句->HAVING子句->ORDER BY子句->SELECT子句->LIMIT子句->最终结果
每个子句执行后都会产生一个中间结果,供接下来的子句使用,如果不存在某个子句,就跳过
对比了一下,mysql和sql执行顺序基本是一样的, 标准顺序的 SQL 语句为:
select 考生姓名, max(总成绩) as max总成绩
from tb_Grade
where 考生姓名 is not null
group by 考生姓名
having max(总成绩) > 600
order by max总成绩
笛卡尔积:
内连接 外连接
见:https://blog.csdn.net/plg17/article/details/78758593
一、内连接
关键字:inner join on
语句:select * from a_table a inner join b_table b on a.a_id = b.b_id;
执行结果:
说明:组合两个表中的记录,返回关联字段相符的记录,也就是返回两个表的交集(阴影)部分。
二、左连接(左外连接)
关键字:left join on / left outer join on
语句:select * from a_table a left join b_table b on a.a_id = b.b_id;
执行结果:
说明:
left join 是left outer join的简写,它的全称是左外连接,是外连接中的一种。
左(外)连接,左表(a_table)的记录将会全部表示出来,而右表(b_table)只会显示符合搜索条件的记录。右表记录不足的地方均为NULL。
三、右连接(右外连接)
关键字:right join on / right outer join on
语句:select * from a_table a right outer join b_table b on a.a_id = b.b_id;
执行结果:
说明:
right join是right outer join的简写,它的全称是右外连接,是外连接中的一种。
与左(外)连接相反,右(外)连接,左表(a_table)只会显示符合搜索条件的记录,而右表(b_table)的记录将会全部表示出来。左表记录不足的地方均为NULL。
父线程怎么获得子线程的返回值
获取Java线程返回值的几种方式
在实际开发过程中,我们有时候会遇到主线程调用子线程,要等待子线程返回的结果来进行下一步动作的业务。
那么怎么获取子线程返回的值呢,我这里总结了三种方式:
主线程等待。
== Join方法等待。==
==实现Callable接口。 ==
Entity类
package com.basic.thread;
public class Entity {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
主线程等待
1 public static void main(String[] args) throws InterruptedException {
2 Entity entity = new Entity();
3 Thread thread = new Thread(new MyRunnable(entity));
4 thread.start();
5 // 获取子线程的返回值:主线程等待法
6 while (entity.getName() == null){
7 Thread.sleep(1000);
8 }
9 System.out.println(entity.getName());
10 }
Join方法阻塞当前线程以等待子线程执行完毕
1 public static void main(String[] args) throws InterruptedException {
2 Entity entity = new Entity();
3 Thread thread = new Thread(new MyRunnable(entity));
4 thread.start();
5 // 获取子线程的返回值:Thread的join方法来阻塞主线程,直到子线程返回
6 thread.join();
7 System.out.println(entity.getName());
8 }
通过实现Callable接口
这里又分为两种情况,通过FutureTask或线程池。
- FutureTask
1 @SuppressWarnings("all")
2 public static void main(String[] args) throws ExecutionException, InterruptedException {
3 FutureTask futureTask = new FutureTask(new MyCallable());
4 Thread thread = new Thread(futureTask);
5 thread.start();
6 if(!futureTask.isDone())
7 System.out.println("task has not finished!");
8 System.out.println(futureTask.get());
9 }
线程池
1 @SuppressWarnings("all")
2 public static void main(String[] args) throws ExecutionException, InterruptedException {
3 ExecutorService executorService = Executors.newCachedThreadPool();
4 Future future = executorService.submit(new MyCallable());
5 if(!future.isDone())
6 System.out.println("task has not finished!");
7 System.out.println(future.get());
8 }
Java开发的框架和技术Spring
详见:https://www.cnblogs.com/kaleidoscope/p/9630131.html
Spring MVC
Spring Boot
Spring Cloud
Hibernate
Spring主要是基于IOC反转Beans管理Bean类,主要依存于SSH框架(Struts+Spring+Hibernate)这个MVC框架,所以定位很明确,
Struts主要负责表示层的显示,
Spring利用它的IOC和AOP来处理控制业务(负责对数据库的操作),
Hibernate主要作用是数据的持久化到数据库。
SpringMVC
是基于Spring
的一个MVC
框架,用以替代初期的SSH框架;(Spring Framework
本身没有Web功能,Spring MVC
使用WebApplicationContext
类扩展ApplicationContext
,使得拥有web功能)。
Spring Boot
是基于Spring4的条件注册的一套快速开发整合包。
三者的发展与联系:
Spring 最初利用“工厂模式”( DI )和“代理模式”( AOP )解耦应用组件。大家觉得挺好用,于是按照这种模式搞了一个 MVC 框架(一些用 Spring 解耦的组件),用开发 web 应用( SpringMVC )。然后有发现每次开发都要搞很多依赖,写很多样板代码很麻烦,于是搞了一些懒人整合包( starter ),这套就是 Spring Boot 。
概念解读
- 什么是Spring
一个轻量级的控制反转(IoC)和面向切面(AOP)的容器 - 什么是SpringMVC
spring与mvc可以更好地解释什么是springMvc,MVC为现代web项目开发的一种很常见的模式,简言之C(控制器)将V(视图、用户客户端)与M(模块,业务)分开构成了MVC ,业内常见的mvc模式的开发框架有Struts1,Struts2等。spring作为专业的开发web项目的开源框架,springMvc为内部的一个模块环节,同样采取mvc设计模式。 - 什么是SpringBoot
Spring boot 是 Spring 的一套快速配置脚手架,可以基于spring boot 快速开发单个微服务,特点:简单易用,初学者和大牛都可以轻松上手,其中的注解会给使用者提供方便;
Spring boot对第三方技术进行了很好的封装和整合,提供了大量第三方接口;
可以通过依赖自动配置,不需要XML等配置文件
深入解读Spring Boot与Spring Boot的概念与关系
Spring Boot
简化了基于 Spring的应用开发,通过少量的代码就能创建一个独立的、产品级別的 Spring应用。 Spring Boot
为 Spring平台及第三方库提供开箱即用的设置,这样你就可以有条不紊地开始。多数 SpringBoot
应用只需要很少的 Spring
配置。
Spring Boot
是由 Pivotal团队提供的全新框架,其设计目的是用来简化新 Spring应用的初始搭建以及开发过程。该框架使用了特定的方式来进行配置,从而使开发人员不再需要定义样板化的配置。用我的话来理解,就是Spring Boot
其实不是什么新的框架,它默认配置了很多框架的使用方式,就像 maven
整合了所有的jar
包,Spring Boot
整合了所有的框架。
Spring Boot
的核心思想就是约定大于配置,一切自动完成。采用 Spring Boot
可以大大的简化你的开发模式,所有你想集成的常用框架,它都有对应的组件支持。
什么是Spring Cloud
Spring Cloud
是一系列框架的有序集合。它利用Spring Boot
的开发便利性巧妙地简化了分布式系统基础设施的开发,如服务发现注册、配置中心、消息总线、负载均衠、断路器、数据监控
等,都可以用 Spring Boot的开发风格做到一键启动和部署。 Spring并没有重复制造轮子,它只是将目前各家公司开发的比较成熟、经得起实际考验的服务框架组台起来,通过 Spring Boot风格进行再封装屏蔽掉了复杂的配置和实现原理,最终给开发者留出了一套简单易懂、易部署和易维护的分布式系統开发工具包。- 微服务是可以独立部署、水平扩展、独立访问(或者有独立的数据库)的服务单元, Spring Cloud就是这些微服务的大管家,采用了微服务这种架构之后,项目的数量会非常多, Spring Cloud做为大管家就需要提供各种方案来维护整个生态。
- Spring Cloud就是一套分布式服务治理的框架,既然它是一套服务治理的框架,那么它本身不会提供具体功能性的操作,更专注于服务之间的通讯、熔断、监控等。因此就需要很多的组件来支持一套功能。
Spring Boot和Spring Cloud的关系
Spring Boot和Spring Cloud的区别
Spring boot是Spring的一套快速配置脚手架,可以基于Spring Boot快速开发单个微服务;Spring Cloud是一个基于Spring Boot实现的云应用开发工具
Spring Boot专注于快速、方便集成的单个个体,Spring Cloud是关注全局的服务治理框架;
Spring boot使用了默认约定大于配置的理念,很多集成方案已经帮你选择好了,能不配置就不配置,Spring Cloud很大的一部分是基于Spring Boot来实现。
Spring Boot可以离开Spring Cloud独立使用开发项目,但是Spring Cloud离不开Spring Boot,属于依赖的关系。
java中的自动装箱和自动拆箱
自动装箱
就是Java自动将原始类型值转换成对应的对象,比如将int的变量转换成Integer对象,这个过程叫做装箱,反之将Integer对象转换成int类型值,这个过程叫做拆箱
。
因为这里的装箱和拆箱是自动进行的非人为转换
,所以就称作为自动装箱和拆箱原始类型
byte,short,char,int,long,float,double和boolean
对应的封装类为Byte,Short,Character,Integer,Long,Float,Double,Boolean。
1 //自动装箱
2 Integer total = 99;
4 //自动拆箱
5 int totalprim = total;
简单一点说,装箱
就是自动将基本数据类型转换为包装器类型;拆箱
就是自动将包装器类型转换为基本数据类型。
java的不可变类型
可变类和不可变类(Mutable and Immutable Objects)的初步定义:
可变类:当你获得这个类的一个实例引用时,你可以改变这个实例的内容。
不可变类:当你获得这个类的一个实例引用时,你不可以改变这个实例的内容。不可变类的实例一但创建,其内在成员变量的值就不能被修改。
如何创建一个自己的不可变类:
- 所有成员都是private
- 不提供对成员的改变方法,例如:setXXXX
- 确保所有的方法不会被重载。手段有两种:使用final Class(强不可变类),或者将所有类方法加上final(弱不可变类)。
- 如果某一个类成员不是原始变量(primitive)或者不可变类,必须通过在成员初始化(in)或者get方法(out)时通过深度clone方法,来确保类的不可变。
在 Java 中 String, BigInteger, BigDecimal
就是这样的类。
有一些很好的理由来说明为什么需要创建不可变类:
线程安全,不需要考虑同步问题
更加安全,能够被自由共享
更不容易出错
设计简单,使用方便
java的运行期异常和非运行期异常
异常的概念
Throwable: 有两个重要的子类:Exception(异常)和 Error(错误),二者都是 Java 异常处理的重要子类,各自都包含大量子类。
Error(错误):是程序无法处理的错误,表示运行应用程序中较严重问题。大多数错误与代码编写者执行的操作无关,而表示代码运行时 JVM(Java 虚拟机)出现的问题。例如,Java虚拟机运行错误(Virtual MachineError),当 JVM 不再有继续执行操作所需的内存资源时,将出现 OutOfMemoryError。这些异常发生时,Java虚拟机(JVM)一般会选择线程终止。
Exception(异常):是程序本身可以处理的异常。
Exception可以分为checked exceptions(非运行时异常)和unchecked exceptions(运行时异常):
- Unchecked Exception
unchecked exceptions在编译时不进行检查。继承自RuntimeException的类,便是unchecked exceptions;
例如:
NullPointerException(空指针异常)、
IndexOutOfBoundsException(下标越界异常)
ClassCastException(类转换异常)
ArrayStoreException(数据存储异常,操作数组时类型不一致)
IO操作的BufferOverflowException异常
- CheckedExceptions
在编译时进行检查的异常称为checked exceptions,也称编译异常。继承Exception的类,除了UncheckedException以外都是checked exceptions;从程序语法角度讲是必须进行处理的异常,如果不处理,程序就不能编译通过。
常见异常:
FileNotFoundException
ParseException
ClassNotFoundException
CloneNotSupportedException
InstantiationException
InterruptedException
NoSuchMethodException
NoSuchFieldException
见:https://blog.csdn.net/qq_25223941/article/details/109648479
对集合对象进行排序是如何实现的
java集合的工具类Collections中提供了两种排序的方法,分别是:
Collections.sort(List list)
Collections.sort(List list,Comparator c)
第一种称为自然排序,参与排序的对象需实现comparable接口,重写其compareTo()方法,方法体中实现对象的比较大小规则,示例如下:
实体类:(基本属性,getter/setter方法,有参无参构造方法,toString方法)
第二种叫定制排序,或自定义排序,需编写匿名内部类,先new一个Comparator接口的比较器对象c,同时实现compare()其方法;
然后将比较器对象c传给Collections.sort()方法的参数列表中,实现排序功能;
java本身排序的方法和工具类
目前java工具类排序分为两种:
数组排序
集合工具类排序
首先要知道两个类:java.util.Arrays和java.util.Collections。我们使用Arrays对数组进行排序,使用 Collections对结合框架容器进行排序(集合(list / set)),如ArraysList,LinkedList等
1.java.util.Arrays类
提供了各种对象的排序:char[],byte[],long[],int[]和Object[],注Arrays.sort方法排序返回的结果是升序Ascending的排列顺序。你可以定制排序顺序。这个排序和TreeSet的红黑树排序方式不同,Set不允许有重复数据存在,因此,当有重复数据时,可以使用这个工具类进行排序。Arrays提供的排序算法是归并排序算法(当元素数量小于=7时采用的是插入排序),空间复杂度O(n)。
2.java.util.Collections类
该工具类提供了大量方法对集合元素进行排序、查询和修改等操作,还提供了将集合对象设置为不可变、对集合对象实现同步控制等方法。
见:https://blog.csdn.net/qiyeliuli/article/details/51446566
Collections.sort(Arrays.asList(strs1),Collections.reverseOrder());
java覆写,隐藏,重载
覆盖/重写/覆写(一个意思!)(Overriding/Overwrite)
重写 重载前面强调过很多次。
这里主要是隐藏 主要是在重写的基础上但作用的是静态方法,
隐藏:父类和子类拥有相同名字的属性或者方法时,父类的同名的属性或者方法形式上不见了,实际是还是存在的
注意:当发生隐藏的时候,声明类型是什么类,就调用对应类的属性或者方法,而不会发生动态绑定
方法隐藏只有一种形式,就是父类和子类存在相同的静态方法 属性只能被隐藏,不能被覆盖
子类实例变量/静态变量可以隐藏父类的实例/静态变量,总结为变量可以交叉隐藏
对于重写,属性静态绑定,方法动态绑定。
使用递归注意哪些东西?使用场景,什么时候可以用,什么时候不可以用,递归主要消耗什么资源
什么情况下用递归?
递归的特点,可以看出递归可以大大缩短程序的代码,有意识的使用递归,可以用较短的代码解决一些复杂的问题。甚至有些问题非得使用递归解决不可。那么什么时候我们该使用递归呢?
递归算法的基本思想是:把规模大的、较难解决的问题变成规模较小的、易解决的同一问题。规模较小的问题又变成规模更小的问题,并且小到一定程度可以直接得出它的解,从而得到原来问题的解。
比如阶乘,也就是说求n可以先求n-1,以此类推,到1,这类问题都可以用递归解决,菲波拉锲数也可以递归。因为递归是总是调用自身解决问题,所以,必须有结束条件,否则会出问题,导致内存卡爆
递归算法:
优点:代码简洁、清晰,并且容易验证正确性。
缺点:它的运行需要较多次数的函数调用,如果调用层数比较深,每次都要创建新的变量,需要增加额外的堆栈处理,会对执行效率有一定影响,占用过多的内存资源。
函数调用 就是 压栈 退栈操作
先将调用函数的地址压栈
分配被调用函数 局部变量分配 形参 返回值 都要分配 调用后一层一层返回
递归自己调用自己多少次 就要分配多少次 局部变量分配 形参 返回值
多核CPU
转:https://zhidao.baidu.com/question/1823797955212689748.html
多核CPU是指一个CPU内有多个运算核心,比如四核心CPU,可以并行运算四个线程的任务。而这些核心都集成在一个CPU中,因此彼此之间的通信很快。
多个CPU是指许多个CPU个体,一般市面上只有最多同时安装两颗CPU的主板,由于两颗CPU需要主板的线路进行交互,所以1+1的性能肯定是小于2的。
比如一颗四核CPU和两颗双核CPU,假定他们除了核心数量不同外其余参数相同,那么一颗四核CPU的性能是好于两颗双核CPU并行的。
哈希碰撞
转:https://blog.csdn.net/kjfcpua/article/details/44238757
如果两个输入串的hash函数的值一样,则称这两个串是一个碰撞(Collision)。既然是把任意长度的字符串变成固定长度的字符串,所以必有一个输出串对应无穷多个输入串,碰撞是必然存在的。
一个优良的hash函数 f 应当满足以下三个条件:
(1)对于任意y,寻找x,使得f(x)=y,在计算上是不可行的。
(2)给定x1∈A,找x2∈B,,使得f(x1)=f(x2),在计算上是不可能的,这也就是弱无碰撞性。
(3)寻找x1,x2,使得f(x1)=f(x2),在计算上也是不可行的,这也就是强无碰撞性。
这样就称为安全保密的Hash函数,除了枚举外不可能有别的更快的方法。如第3条,根据生日定理,要想找到这样的x1,x2,理论上需要大约2^(n/2)的枚举次数。
因为前两条都能被破坏的hash函数太弱而被抛弃,几乎所有的hash函数的破解,都是指的破坏上面的第3条性质,即找到一个碰撞。在密码学上还有一个概念是理论破解,指的是提出一个算法,使得可以用低于理论值得枚举次数找到碰撞。
4、碰撞处理
通常有两类方法处理碰撞:开放寻址(Open Addressing)法和链接(Chaining)法。前者是将所有结点均存放在散列表T[0…m-1]中;后者通常是把散列到同一槽中的所有元素放在一个链表中,而将此链表的头指针放在散列表T[0…m-1]中。
(1)开放寻址法
所有的元素都在散列表中,每一个表项或包含动态集合的一个元素,或包含NIL。这种方法中散列表可能被填满,以致于不能插入任何新的元素。在开放寻址法中,当要插入一个元素时,可以连续地检查或探测散列表的各项,直到有一个空槽来放置待插入的关键字为止。有三种技术用于开放寻址法:线性探测、二次探测以及双重探测。
<1>线性探测
给定一个普通的散列函数h’:U —>{0,1,…,m-1},线性探测方法采用的散列函数为:h(k,i) = (h’(k)+i)mod m,i=0,1,…,m-1
探测时从i=0开始,首先探查T[h'(k)],然后依次探测T[h'(k)+1],…,直到T[h'(k)+m-1],此后又循环到T[0],T[1],…,直到探测到T[h'(k)-1]为止。探测过程终止于三种情况:
(1)若当前探测的单元为空,则表示查找失败(若是插入则将key写入其中);
(2)若当前探测的单元中含有key,则查找成功,但对于插入意味着失败;
(3)若探测到T[h’(k)-1]时仍未发现空单元也未找到key,则无论是查找还是插入均意味着失败(此时表满)。
线性探测方法较容易实现,但是存在一次群集问题,即连续被占用的槽的序列变的越来越长。采用例子进行说明线性探测过程,已知一组关键字为(26,36,41,38,44,15,68,12,6,51),用除余法构造散列函数,初始情况如下图所示:
散列过程如下图所示:
<2>二次探测
二次探测法的探查序列是:h(k,i) =(h’(k)+i*i)%m ,0≤i≤m-1 。初次的探测位置为T[h’(k)],后序的探测位置在次基础上加一个偏移量,该偏移量以二次的方式依赖于i。该方法的缺陷是不易探查到整个散列空间。
<3>双重散列
该方法是开放寻址的最好方法之一,因为其产生的排列具有随机选择的排列的许多特性。采用的散列函数为:h(k,i)=(h1(k)+ih2(k)) mod m。其中h1和h2为辅助散列函数。初始探测位置为T[h1(k)],后续的探测位置在此基础上加上偏移量h2(k)模m。
(2)链接法
将所有关键字为同义词的结点链接在同一个链表中。若选定的散列表长度为m,则可将散列表定义为一个由m个头指针组成的指针数组T[0…m-1]。凡是散列地址为i的结点,均插入到以T[i]为头指针的单链表中。T中各分量的初值均应为空指针。在拉链法中,装填因子α可以大于1,但一般均取α≤1。
举例说明链接法的执行过程,设有一组关键字为(26,36,41,38,44,15,68,12,6,51),用除余法构造散列函数,初始情况如下图所示:
最终结果如下图所示:
b树和b+树的区别
转:https://blog.csdn.net/login_sonata/article/details/75268075
b树(balance tree)和b+树应用在数据库索引,可以认为是m叉的多路平衡查找树,但是从理论上讲,二叉树查找速度和比较次数都是最小的,为什么不用二叉树呢?
因为我们要考虑磁盘IO的影响,它相对于内存来说是很慢的。数据库索引是存储在磁盘上的,当数据量大时,就不能把整个索引全部加载到内存了,只能逐一加载每一个磁盘页(对应索引树的节点)。所以我们要减少IO次数,对于树来说,IO次数就是树的高度,而“矮胖”就是b树的特征之一,它的每个节点最多包含m个孩子,m称为b树的阶,m的大小取决于磁盘页的大小。
实用索引不出现Using filesort
转:https://blog.csdn.net/nrsc272420199/article/details/104698404
不会出现 Using filesort的情况 — 符合最佳左前缀法则
order by也满足索引最佳左前缀法则的时候
— order by a
— order by a, b
— order by a,b,c
— order by a desc,b desc ,c desc
explain select age, birth,name from tbl where age >10 order by age;
explain select age, birth,name from tbl where age >10 order by age,birth;
explain select age, birth,name from tbl where age >10 order by age,birth,name;
explain select age, birth,name from tbl where age >10 order by age desc,birth desc,name desc;
假如我将查询的内容改为 * ,我们再来看一下其执行计划:
在进行 大于 查询时,mysql会找到你的目标条件在索引树上的最小值,假如你指定的值,比索引树上的最小值还小,那肯定就是要查询所有的数据了,那mysql就懒得再去遍历你目标条件所在的索引树了,而是直接通过聚簇索引搜索出所有数据。