使用二分法Arrays.binarySearch()与list.contains()进行元素比较的效率分析
来源:互联网 发布:程序员修炼之道pdf高清 编辑:程序博客网 时间:2024/05/19 22:04
有这样一个简单的场景,需要把Excel存储的以下格式的物料数据上传到系统里,但是系统的数据库已经存在大量的记录,例如几十万条记录。而业务 上的约束条件是对于同一个PLANT下,不允许存在重复的Material,数据库的设计也是将PLANT和MATERIAL_NO作为联合主键,如果从 Excel导入的数据对于数据库中已经存在的数据重复,那么也会抛出主键唯一约束异常。
Excel数据格式:
PLANTMATERIAL_NOMTYPEMATERIAL_DESP6030101-002876ROHMATE_DESP6030101-002877ROHMATE_DESP6040101-002878ROHMATE_DESP6040101-002879ROHMATE_DES
数据库表结构(SqlServer2008)
TB_WASTER_MATE
对于这种需求,如果不考虑性能和效率,在数据较少的情况下,我们常见的的解决方案是读取所有的Excel数据构成一个Material List,
循环此List,取List中每个Material,根据Material对象的PLANT和MATE_NO属性去查询数据中是否存在这样的记录,如果存在,跳过,如果不存在,插入这条数据到数据库,返回给用户操作结果。
那么在大数据量的情况下,这样做的弊端是显而易见的,主要就是数据库的访问太频繁,每插入一条记录就得做一次select操作。
那如何减少数据库访问次数呢?显然将数据库表中数据一次性查询全部取出组成一个Material对象List,然后调用List对象的 contains()方法判断此List是否包含了待插入的Material可能是比较好的一个方法。但是这样做也存在一些问题,1.一次性全部取出并组 装成Material对象,对内存的开销比较大,如果是比较大的对象,而且内存有限,有可能导致内存溢出;2.首先Material类需要重写 equals()方法,对于每条待插入的数据都需要调用contains()方法,调用contains方法时,默认是将contains方法的参数和 List中的数据遍历比较,对于Material对象,需要不断的调用equals()方法来比较这个对象和List中的元素对象是否相等。假设数据库查 出来的Material记录有10000条,最坏的情况,需要插入的数据和第10000条数据重复或和10000条都不重复,那么equals()方法需 要被调用10000次。
更好的解决方案是查询出PLANT和MATE_NO的连接字符串,并且排好序
SELECT (PLANT+MATE_NO) as MATEINFO FROM TB_WASTER_MATE ORDER BY MATEINFO
得到诸如:
P6030101-002876
P6030101-002877
P6040101-002878
P6040101-002879
形式的数据
将查出的所有数据组合成字符串数组,调用数组的二分查找方法Arrays.binarySearch()来判断待插入的数据是否在数据库中已存在, 二分法查找需要被查找的数组已经是排好序的,而sql查询时已经将顺序排好,所以数组可以直接使用,这样不仅将数据库查询减少到仅有一次,而且每次将查找 范围缩小一半,元素比较的效率大大提高。
下面来比较测试一下两种方法的效率差异:
- import java.util.ArrayList;
- import java.util.List;
- import java.util.Arrays;
- /**
- * ClassName:EffCompare.java
- * Author: Jack0511
- * CreateTime: Feb 28, 2011 2:50:23 PM
- * Description:
- **/
- public class EffCompare {
- /**
- * @param args
- */
- public static void main(String[] args) {
- List<String> list = new ArrayList<String>(10000);
- for(int i=0;i<100000;i++){
- list.add("jack"+i);
- }
- String[] array = list.toArray(new String[10000]);
- Arrays.sort(array);
- long begin = System.currentTimeMillis();
- for(int k=60000;k<70000;k++){ //1
- int index = Arrays.binarySearch(array, "jack"+k);
- //System.out.println(Arrays.binarySearch(array, "jack"+k));
- }
- long end = System.currentTimeMillis();
- System.out.println("二分法查找10000个item消耗:"+(end-begin)+"毫秒");
- begin = System.currentTimeMillis();
- for(int n=60000;n<70000;n++){ //2
- boolean i***ist = list.contains("jack"+n);
- //System.out.println(list.contains("jack"+n));
- }
- end = System.currentTimeMillis();
- System.out.println("contains查找10000个item消耗:"+(end-begin)+"毫秒");
- }
- }
结果:
二分法查找10000个item消耗:0毫秒
contains查找10000个item消耗:12453毫秒
测试的时候可以将 1,2 处的代码改为for(int n=0;n<10000;n++){ ,
for(int n=90000;n<100000;n++){
可以发现,起始值越往后,二分法的耗时基本不变,而用contains()比较的耗时越来越大,原因当然是contains方法进行了越来越多的equals()调用。
- 使用二分法Arrays.binarySearch()与list.contains()进行元素比较的效率分析
- 使用二分法Arrays.binarySearch()与list.contains()进行元素比较的效率分析
- 使用二分法Arrays.binarySearch()与list.contains()进行元素比较的效率分析
- Arrays.binarySearch(二分法检索)
- 二分法与简单遍历的效率比较
- 二分法与简单遍历的效率比较
- Indexof与BinarySearch的比较
- List<T>线性查找和二分查找BinarySearch效率分析
- 定义二分法查找数组中的数,实现arrays.binarySearch()int类型的功能。
- Interpolation Search与BinarySearch的比较
- java中使用Arrays.binarySearch()在数组中查找指定元素
- Arrays.binarySearch()
- Arrays.binarySearch();
- Arrays.binarySearch
- 在154个元素组成有序表进行二分法查找,可能的比较次数为
- 在154个元素组成有序表进行二分法查找,可能的比较次数为()
- java关于ArrayList动态数组与静态数组Arrays-元素比较输出最大最小值的使用例子
- list与vector的尾部插入删除效率比较
- android 自定义ScrollView实现反弹效果(以及解决和ListView之间的冲突)
- 推荐一款图表生成工具-FusionCharts
- MyBatis的动态SQL详解
- 处理命令行选项
- hibernate
- 使用二分法Arrays.binarySearch()与list.contains()进行元素比较的效率分析
- asp.net生成excel
- Project Euler 29
- 防止touch事件穿层从而触发下层menu响应
- android 复制、剪切、粘贴
- InputStream转换String三种方式
- ural1707 线段树扫描线
- C语言中scanf()的用法
- 雅思口语 第一章 最爱的人最难忘