大数据量查询优化_精准大数据获客系统

大数据 (2) 2024-06-25 12:23

Hi,大家好,我是编程小6,很荣幸遇见你,我把这些年在开发过程中遇到的问题或想法写出来,今天说一说
大数据量查询优化_精准大数据获客系统,希望能够帮助你!!!。

问题描述:涉及到大数据量,多循环查询的时候,往往查询的速度会变慢,影响系统的使用性能。该问题,在测试环境尚不明显,因为测试环境的数据量毕竟是有限的。

但是,一旦将代码更新到线上的真实系统,因为数据量一下子增大,会造成数据查询的缓慢,所造成的严重迟滞,就不能被忽略了。

业务场景:云计算系统。底层会将采集过来的宿主机流量数据,进行保存。后台管理系统,需要定时计算从底层传递过来的宿主机的带宽的总体实际使用量,并且用实际使用量,除以节点的总带宽,得到相关的出网、入网的带宽使用率。

方案分析:
1.在保存数据的时候,事实计算出数据使用量,后续查询时,通过sql语句的sum方法直接汇总。
2.开启多线程并发查询。

一、利用Callable多线程,实现查询优化的例子

原理同一个Callable的简单例子。核心在于运用多线程,创建带有返回值的查询。

1.准备查询参数

2.根据每页数据量,去判断应该创建的线程的数量。

3.根据数据的总数量,平均分配每个线程处理的数量。

4.将查询返回的Future,保存在list中(注意,这样做可以提升查询速度,先批量保存结果,再处理的方式,要快于拿到值就处理的方式)

5.        latch.await();

6.遍历List,数据处理+分页,返回数据值。

public String services(){ List <Future<Map<String,Object>>> list=new ArrayList<Future<Map<String,Object>>>(); int total=0; //1.准备需要传递的参数 String condition = dealContent(); List<CompanyEntity> companyList = companyService.list(condition, -1, -1); List<Node> nodeList = new ArrayList<Node>(); int nodeId = getNodeId(); if(nodeId != 0){ Node node = nodeService.getById(nodeId); nodeList.add(node); }else{ nodeList = nodeService.getAll(); } List<JSONObject> comList = new ArrayList<JSONObject>(); for(CompanyEntity company : companyList){ for(Node node : nodeList){ JSONObject jsonObj = new JSONObject(); jsonObj.put("companyName", company.getCompanyName()); jsonObj.put("companyId", company.getCompanyId()); jsonObj.put("companyType", company.getType()); jsonObj.put("nodeName",node.getNode_name()); jsonObj.put("nodeId",node.getNode_id()); jsonObj.put("nodeIp", node.getNode_ip()); comList.add(jsonObj); } } //2.数据分页处理 int pagesize=Integer.parseInt(super.getPagesize()); int nopage=Integer.parseInt(super.getNowpage()); int ThrearNum=0; if(pagesize>ThreadUtil.CORE_POOL_SIZE){ ThrearNum=ThreadUtil.CORE_POOL_SIZE; }else{ ThrearNum=pagesize; } try { //计算数据总量: int sumDataCount=comList.size(); List<JSONObject> dataList=new ArrayList<JSONObject>(); final CountDownLatch latch = new CountDownLatch(ThrearNum); boolean flag=false; int dataEnd=0; int addData=0; int j=1; for (int i = 0; i < ThrearNum; i++) { List<JSONObject> addList=new ArrayList<JSONObject>(); List<JSONObject> tempList=new ArrayList<JSONObject>(comList.size()); tempList=comList; List<JSONObject> dealList=new ArrayList<JSONObject>(); if(sumDataCount%ThrearNum!=0){ addData=sumDataCount%ThrearNum; flag=true; } //计算每个线程要处理的数据总量: int dataCountPerThread=sumDataCount/ThrearNum; //计算当前线程数据处理的起始索引: int dataStart=i*dataCountPerThread; //计算当前线程数据处理的结束索引: dataEnd=(i+1)*dataCountPerThread; //截取List,作为当前线程所需要处理的全部数据: if(flag){ if(j<=addData){ //多余的数据,从最后的索引开始平均分配 addList.add(tempList.get(tempList.size()-j)); j++; } dealList=subData(tempList,dataStart, dataEnd); if(addList.size()!=0){ dealList.add(addList.get(0)); addList.remove(0); } }else{ dealList=subData(tempList,dataStart, dataEnd); //如果这里不使用subData,而是使用subList,则会报错:java.util.ConcurrentModificationException //dealList=comList.subList(dataStart, dataEnd); } Callable<Map<String,Object>> c1 = new CallableCountThread(condition,dealList,VpcFlag,slbFlag,blockFlag,vpnFlag,latch); Future<Map<String,Object>> f1=pool.submit(c1); list.add(f1); } latch.await(); for(int i=0;i<list.size();i++){ Future<Map<String,Object>> f1=list.get(i); total+=(Integer)f1.get().get("count"); if(null!=f1.get().get("data")){ dataList.addAll((List<JSONObject>)f1.get().get("data")); } } doPage_special(total); //3.查询分页开始和结束的索引位 int nowpage2 = (Integer) dataMap.get("nowpage"); int pagesize2 = (Integer) dataMap.get("pagesize"); List<JSONObject> showData=new ArrayList<JSONObject>(); if(dataList.size()==0){ }else{ if(nopage==1){ if(dataList.size()<=pagesize2){ showData=dataList.subList(0,dataList.size()-1); showData.add(dataList.get(dataList.size()-1)); }else{ showData=dataList.subList(0,pagesize2); } }else{ if(dataList.size()<=(nopage)*pagesize2){ showData=dataList.subList((nopage-1)*pagesize2,dataList.size()-1); showData.add(dataList.get(dataList.size()-1)); }else{ showData=dataList.subList((nopage-1)*pagesize2,nopage*pagesize2); } } } generateSuccessListResponse(showData); } catch (InterruptedException | ExecutionException e) { // TODO Auto-generated catch block e.printStackTrace(); } return JSON; }

二、查询效率

没有使用duox多线程:

 

大数据量查询优化_精准大数据获客系统_https://bianchenghao6.com/blog_大数据_第1张

查询时间在16s左右

 

使用多线程查询:

大数据量查询优化_精准大数据获客系统_https://bianchenghao6.com/blog_大数据_第2张

查询时间在1.7s左右

 

查询速度提升了十倍。

 

三、心得总结:

1.写代码的时候,不能仅仅只考虑功能的实现。特别是涉及到数据量比较大的时候,任何一次查询的精简,带来的效率提升都是显著的。

2.多线程在具体场景中的使用是非常重要的。在涉及到返回值的时候,就需要使用到Callable接口。

3.任何时候,写完代码,都要自己给自己做code review。回过头去看看自己写的代码。能不能优化,能不能再优化。

 

今天的分享到此就结束了,感谢您的阅读,如果确实帮到您,您可以动动手指转发给其他人。

发表回复