批量資料結構緩衝載入資料二叉樹查詢的效率優化測試
問題:
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倍以上!