批量数据结构缓冲加载数据二叉树查找的效率优化测试

来源:互联网 发布:黄金交易软件出租 编辑:程序博客网 时间:2024/05/09 10:08

问题:
2009年12月10日,在开发客户维系挽留系统时,进行Bi_Subscrb_Cdr基础数据表抽取初步测试时,发现效率奇低。
原因有以下可能:
1.数据库主机忙,导致上载数据到内存中时,速度过慢。
2.网络繁忙(网速确实很慢),由于当时是前台交互执行程序,但是这个应该影响不大。
3.程序所在主机忙,这个可能性更小。
4.程序本身的数据结构问题。

测试:
1.通过对其他程序测试,比较该程序以往的运行日志,排除数据库和程序主机及网络的主要影响因素。
2.对程序分析:批量数据结构缓冲加载数据二叉树查找时,在数据上载内存平衡二叉树中的时候,
有个数据排序插入链表的过程,这个对后续数据的处理可能会提供一定的帮助。
但是当外来数据要进行多字段累加操作时,再对数据进行排序插入链表时,就会很大程度上影响
数据上载二叉树时的效率...

部分源程序如下:

/*批量数据结构缓冲加载数据二叉树查找*/
int ESearchBiSubscrbCdrBinTree(void *pi,struct BiSubscrbCdrStruct **p,char sTableName[],char sCondition[])
{
 static int iFirstFlag=TRUE;
 BINTREE *ptHead=pEBiSubscrbCdrBinTree;

 if(pi==NULL){

  /*调用bintree_free_bi_subscrb_cdr函数释放内存*/
  TravelBinTree(ptHead,bintree_free_bi_subscrb_cdr);
  iFirstFlag=TRUE;
  pEBiSubscrbCdrBinTree = NULL;

  return TRUE;
 }

 if(iFirstFlag){
  struct BiSubscrbCdrStruct *pBinTree;
  struct BiSubscrbCdrStruct Temp;
  struct BiSubscrbCdrStructIn TempIn;

  bzero((void*)&TempIn,sizeof(struct BiSubscrbCdrStructIn));
  if(strlen(sTableName)!=0){
   strcpy(TempIn.sTableName,sTableName);
   strcpy(TempIn.sCondition,sCondition);
  }
  else{
   strcpy(TempIn.sTableName,"BI_SUBSCRB_CDR");
   strcpy(TempIn.sCondition,"");
  }
  TempIn.iBufEmpty =TRUE;
  TempIn.iFirstFlag = TRUE;

  TravelBinTree(ptHead,bintree_free_bi_subscrb_cdr);
  
  /*逐条获取BI_SUBSCRB_CDR 数据进行处理*/
  while(EGetBiSubscrbCdrToStruct(&Temp,&TempIn)){

   pBinTree=(struct BiSubscrbCdrStruct *)malloc(sizeof(struct BiSubscrbCdrStruct));
   if(pBinTree==NULL){
    printf("error Malloc BinTree for BiSubscrbCdrStruct./n");
    exit(1);
   }

   memcpy(pBinTree,(void *)&Temp,sizeof(struct BiSubscrbCdrStruct));

   /*比较外来节点和被比较节点大小并将外来数据加载到平衡二叉树中*/
   AdjustInsertExt(&ptHead,pBinTree,bintree_sort_bi_subscrb_cdr,
    bintree_insert_bi_subscrb_cdr);

  }

  pEBiSubscrbCdrBinTree=ptHead;
  iFirstFlag=FALSE;

 }
 return SearchBinTree(ptHead,pi,bintree_search_bi_subscrb_cdr,(void **)p);
}

/*函数原形int (*pFunction)(void *,void*)*/
/*该函数用于SearchBinTree比较外来数据(参数1)和被比较节点数据大小*/
int bintree_search_bi_subscrb_cdr(void *pValue,void*pData)
{
 struct BiSubscrbCdrStruct *pSource=(struct BiSubscrbCdrStruct *)pValue;
 struct BiSubscrbCdrStruct *pTarget=(struct BiSubscrbCdrStruct *)pData;

/*数据比较部分*/
 int res=0;

 if((res=strcmp(pSource->sBillingcyclid,pTarget->sBillingcyclid))!=0) return res;
 if((res=(pSource->iSubscrbid-pTarget->iSubscrbid))!=0) return res;
 if((res=strcmp(pSource->sAreaid,pTarget->sAreaid))!=0) return res;

 return res;
}

/*函数原形void (*pAssign)(BINTREE *,void *)*/
/*该函数用于将外来数据加载到平衡二叉树中*/
/*pHead指针指向的数据不为空*/
void bintree_insert_bi_subscrb_cdr(BINTREE *pHead,void *pData)
{
 struct BiSubscrbCdrStruct *pValue=(struct BiSubscrbCdrStruct *)pData;
 struct BiSubscrbCdrStruct **ppLkHead=(struct BiSubscrbCdrStruct **)&(pHead->pData);

/*直接插入链表头节点模式*/
/*{
 InsertList((LIST**)(&(pHead->pData)),(LIST*)pData);
}*/
/*排序插入链表,内部调用链表排序函数,默认用*/
/*{
 InsertListSort((LIST**)(&(pHead->pData)),(LIST*)pData,list_sort_bi_subscrb_cdr);
}*/
/*排序插入链表相同累加,内存是否用去可看是否调用,sort_sum_list*/

 InsertListSortSum((LIST**)(&(pHead->pData)),
   (LIST*)pData,list_sort_bi_subscrb_cdr,list_sum_bi_subscrb_cdr);
}

int list_sort_bi_subscrb_cdr(LIST *pValue,LIST*pHead)
{
 struct BiSubscrbCdrStruct *pSource=(struct BiSubscrbCdrStruct *)pValue;
 struct BiSubscrbCdrStruct *pTarget=(struct BiSubscrbCdrStruct *)pHead;
/*加入生成链表的外部数据与链表数据的比较代码*/

/*数据比较部分*/
 int res=0;
/*按主键进行查找*/
 if((res=strcmp(pSource->sBillingcyclid,pTarget->sBillingcyclid))!=0) return res;
 if((res=(pSource->iSubscrbid-pTarget->iSubscrbid))!=0) return res;
 if((res=strcmp(pSource->sAreaid,pTarget->sAreaid))!=0) return res;

 return res;
}

void list_sum_bi_subscrb_cdr(LIST *pValue,LIST*pHead)
{

 struct BiSubscrbCdrStruct *pSource=(struct BiSubscrbCdrStruct *)pValue;
 struct BiSubscrbCdrStruct *pTarget=(struct BiSubscrbCdrStruct *)pHead;

 /*对以下字段作SUM操作*/ 
 pSource->iCallDura+=pTarget->iCallDura;
 pSource->iMoDura+=pTarget->iMoDura;
 pSource->iMtDura+=pTarget->iMtDura;
 pSource->iTrsDura+=pTarget->iTrsDura;
 pSource->iMoLandDura+=pTarget->iMoLandDura;
 pSource->iMtLandDura+=pTarget->iMtLandDura;
 pSource->iRoamDura+=pTarget->iRoamDura;
 pSource->iMoLocalDura+=pTarget->iMoLocalDura;
 pSource->iMtLocalDura+=pTarget->iMtLocalDura;
 pSource->iCallCmccDura+=pTarget->iCallCmccDura;
 pSource->iCallCtcDura+=pTarget->iCallCtcDura;
 pSource->iCallCncDura+=pTarget->iCallCncDura;

 pSource->iCallCnt+=pTarget->iCallCnt;
 pSource->iMoCnt+=pTarget->iMoCnt;
 pSource->iMtCnt+=pTarget->iMtCnt;
 pSource->iTrsCnt+=pTarget->iTrsCnt;
 pSource->iLandCnt+=pTarget->iLandCnt;
 pSource->iRoamCnt+=pTarget->iRoamCnt;
 pSource->iMoCucCnt+=pTarget->iMoCucCnt;
 pSource->iMtCucCnt+=pTarget->iMtCucCnt;
 pSource->iMoCmccCnt+=pTarget->iMoCmccCnt;
 pSource->iMtCmccCnt+=pTarget->iMtCmccCnt;
 pSource->iMoCtcCnt+=pTarget->iMoCtcCnt;
 pSource->iMtCtcCnt+=pTarget->iMtCtcCnt;
 pSource->iMoCncCnt+=pTarget->iMoCncCnt;
 pSource->iMtCncCnt+=pTarget->iMtCncCnt;
 pSource->iMoOthCnt+=pTarget->iMoOthCnt;
 pSource->iMtOthCnt+=pTarget->iMtOthCnt;
 pSource->iMo10010Cnt+=pTarget->iMo10010Cnt;
 pSource->iMt10010Cnt+=pTarget->iMt10010Cnt;
 pSource->iMo10086Cnt+=pTarget->iMo10086Cnt;
 pSource->iMt10086Cnt+=pTarget->iMt10086Cnt;
 pSource->iMo10000Cnt+=pTarget->iMo10000Cnt;
 pSource->iMt10000Cnt+=pTarget->iMt10000Cnt;
 pSource->iMo100060Cnt+=pTarget->iMo100060Cnt;
 pSource->iMt100060Cnt+=pTarget->iMt100060Cnt;
 pSource->iMoOthServCnt+=pTarget->iMoOthServCnt;
 pSource->iMtOthServCnt+=pTarget->iMtOthServCnt;
 pSource->iTrsInnerCnt+=pTarget->iTrsInnerCnt;
 pSource->iTrsIntrCnt+=pTarget->iTrsIntrCnt;
 pSource->iTrsCmccCnt+=pTarget->iTrsCmccCnt;
 pSource->iTrsCtcPstnCnt+=pTarget->iTrsCtcPstnCnt;
 pSource->iTrsCncPstnCnt+=pTarget->iTrsCncPstnCnt;
 pSource->iTrsCtcPhsCnt+=pTarget->iTrsCtcPhsCnt;
 pSource->iTrsCncPhsCnt+=pTarget->iTrsCncPhsCnt;

 free(pTarget);
}

运行测试结果:
--原程序
--处理数据 4000000条记录
--启动时间 2009-12-11 10:50:24
--结束时间 2009-12-11 11:07:45
--统计结果 平均每秒处理数据 3887条,有效率逐渐降低现象(初始8333条/秒,处理到400w数据时2381条/秒)

改进1:先去掉排序插入链表函数功能
int list_sort_bi_subscrb_cdr(LIST *pValue,LIST*pHead)
{
 return 0;
}

运行测试结果:
--去掉排序插入链表
--处理数据 3774982
--启动时间 2009-12-11 10:43:38
--结束时间 2009-12-11 10:44:53
--统计结果 平均每秒处理数据 50333条,无效率降低现象

改进2:再缩小上载数据范围,按单主键比较数据
int bintree_search_bi_subscrb_cdr(void *pValue,void*pData)
{
 struct BiSubscrbCdrStruct *pSource=(struct BiSubscrbCdrStruct *)pValue;
 struct BiSubscrbCdrStruct *pTarget=(struct BiSubscrbCdrStruct *)pData;

/*数据比较部分*/
 int res=0;

 /*if((res=strcmp(pSource->sBillingcyclid,pTarget->sBillingcyclid))!=0) return res;*/
 if((res=(pSource->iSubscrbid-pTarget->iSubscrbid))!=0) return res;
 /*if((res=strcmp(pSource->sAreaid,pTarget->sAreaid))!=0) return res;*/

 return res;

运行测试结果:
--处理数据 4060334
--启动时间 2009-12-11 10:41:31
--结束时间 2009-12-11 10:42:31
--统计结果 平均每秒处理数据 67672,无效率降低现象

(注:测试时间颠倒的原因是由于程序改进后逐步回退测试的结果)

总结:
当大批量数据上载内存时,如果需要对大量字段进行SUM操作时,那么就要考虑数据处理的效率问题了。
当时在跑遍历语音表的时候,其他地市还好数据不多,平均500万左右,但是A地市有3000多万,B地市也有1000多万。
原程序在运行过程中,当处理数据超过600万时,速度明显下降。当处理到1000万以上时,每10万条数据差不多要6分钟。
如果按照这个效率的话,全省每个月近9000万条的数据量可能一两天都处理不完...
程序改进后,平均每10万数据1.5 秒,9000万条数据只要22.5 分钟就能处理完成,效率提高将近100倍以上!

原创粉丝点击