ColdFusion 내에서 .NET AD의 데이터 검색 속도를 높이려면 어떻게 해야 합니까?
-
01-07-2019 - |
문제
현재 100,000개 이상의 레코드 풀에서 800개 이상의 레코드를 검색하고 반복하여 레코드당 6개의 필드를 반환하는 데 2분 이상이 소요되는 다음 코드를 어떻게 최적화할 수 있습니까(추가 필드당 약 20초 추가):
<cfset dllPath="C:\WINDOWS\Microsoft.NET\Framework\v1.1.4322\System.DirectoryServices.dll" />
<cfset LDAPPath="LDAP://" & arguments.searchPath />
<cfset theLookUp=CreateObject(".NET","System.DirectoryServices.DirectoryEntry", dllPath).init(LDAPPath) />
<cfset theSearch=CreateObject(".NET","System.DirectoryServices.DirectorySearcher", dllPath).init(theLookUp) />
<cfset theSearch.Set_Filter(arguments.theFilter) />
<cfset theObject = theSearch.FindAll() />
<cfloop index="row" from="#startRow#" to="#endRow#">
<cfset QueryAddRow(theQuery) />
<cfloop list="#columnList#" index="col">
<cfloop from="0" to="#theObject.Get_Item(row).Get_Properties().Get_Item(col).Get_Count()-1#" index="item">
<cftry>
<cfset theQuery[col][theQuery.recordCount]=ListAppend(theQuery[col][theQuery.recordCount],theObject.Get_Item(row).Get_Properties().Get_Item(col).Get_Item(item),"|") />
<cfcatch type="any">
</cfcatch>
</cftry>
</cfloop>
</cfloop>
</cfloop>
해결책
내부 루프의 항목 목록은 얼마나 됩니까?
어레이로 전환 ~할 것 같다 항목 수가 상당히 많으면 더 빠릅니다.
나는 x0n의 제안과 함께 이것을 구현했습니다 ...
<cfset dllPath="C:\WINDOWS\Microsoft.NET\Framework\v1.1.4322\System.DirectoryServices.dll" />
<cfset LDAPPath="LDAP://" & arguments.searchPath />
<cfset theLookUp=CreateObject(".NET","System.DirectoryServices.DirectoryEntry", dllPath).init(LDAPPath) />
<cfset theSearch=CreateObject(".NET","System.DirectoryServices.DirectorySearcher", dllPath).init(theLookUp) />
<cfset theSearch.Set_Filter(arguments.theFilter) />
<cfset theObject = theSearch.FindAll() />
<cfloop index="row" from="#startRow#" to="#endRow#">
<cfset Props = theObject.get_item(row).get_properties() />
<cfset QueryAddRow(theQuery) />
<cfloop list="#columnList#" index="col">
<cfset CurrentCol = Props.getItem(col) />
<cfset ItemArray = ArrayNew(1)/>
<cfloop from="0" to="#CurrentCol.getcount() - 1#" index="item">
<cftry>
<cfset ArrayAppend( ItemArray , CurrentCol.Get_Item(item) )/>
<cfcatch type="any">
</cfcatch>
</cftry>
</cfloop>
<cfset theQuery[col][theQuery.recordCount] = ArrayToList( ItemArray , '|' )/>
</cfloop>
</cfloop>
다른 팁
오랜만에 CF를 접했는데, 의사코드로 힌트를 좀 드릴 수 있겠네요.우선 이 표현은 매우 비효율적입니다.
#theObject.Get_Item(row).Get_Properties().Get_Item(col).Get_Count()-1#
예를 들어 첫 번째 부분인 Get_Item(row)을 선택합니다. 코드를 사용하면 CF가 #columnList# 루프의 각 반복에 대해 행과 해당 속성을 검색하게 됩니다.그리고 무엇보다도 열 목록 반복마다 두 번 수행합니다(루프에 대해 한 번, 내부 cfset에 대해 다시 한 번).생각해 보면 외부 루프의 각 반복(#sfstart#에서 #cfend까지)에 대한 행만 검색하면 됩니다.따라서 의사 코드에서는 다음을 수행합니다.
시작과 끝 사이의 각 행에 대해
cfset props = #theobject.get_item(row).get_properties()#
#columnlist#의 각 열에 대해
cfset currentcol = #props.getitem(col)#
cfset 개수 = #currentcol.getcount() - 1#
0부터 #count#까지 각 항목에 대해
cfset #currentcol.getItem(item)# 등...
말이 되나요?루프에 들어갈 때마다 해당 범위(또는 하위 범위)에서 재사용될 개체를 변수에 캐시합니다.이는 열 루프를 반복할 때마다 열 개체를 한 번만 잡는다는 의미입니다.위에서 수행한 작업에서 볼 수 있듯이 외부 범위에 정의된 모든 변수는 내부 범위에서 사용할 수 있습니다.이전 줄에서 잘라내어 붙여넣고 싶은 마음이 들지만 그렇지 않습니다.결국에는 당신에게만 상처를 입힐 뿐입니다.
도움이 되었기를 바랍니다,
오이신
또한 각 루프에서 cftry 블록을 사용하면 속도가 상당히 느려질 수 있습니다.개별 행이 실패할 것으로 예상되지 않는 한(그리고 해당 지점부터 계속해야 하는 경우) 전체 프로세스에 대해 단일 try/catch 블록을 제안합니다.Try/catch는 비용이 많이 드는 작업입니다.
루프 내에서 너무 많은 평가를 중단하고 대신 변수를 사용하여 개수, col 객체에 대한 포인터 및 쿼리 객체에 커밋할 준비가 될 때까지 파이프 구분 문자열을 유지하고 싶다고 생각합니다. .리팩토링을 올바르게 수행했다면 아래 코드를 사용하면 개선된 점을 알 수 있습니다.
<cfloop index="row" from="#startRow#" to="#endRow#">
<cfset QueryAddRow(theQuery) />
<cfloop list="#columnList#" index="col">
<cfset PipedVals = "">
<cfset theItem = theObject.Get_Item(row).Get_Properties().Get_Item(col)>
<cfset ColCount = theItem.Get_Count()-1>
<cfloop from="0" to="#ColCount#" index="item">
<cftry>
<cfset PipedVals = ListAppend(PipedVals,theItem.Get_Item(item),"|")>
<cfcatch type="any"></cfcatch>
</cftry>
</cfloop>
<cfset QuerySetCell(theQuery,col) = PipedVals>
</cfloop>