如何在ColdFusion中加快从.NET AD的数据检索?

时间:2020-03-05 18:59:14  来源:igfitidea点击:

我如何优化以下代码,当前从超过10万条记录的池中检索和循环遍历800多个记录需要花费2分钟的时间,每条记录返回6个字段(每增加一个字段大约增加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>

解决方案

回答

自接触CF以来已经有很长时间了,但是我可以用伪代码给出一些提示。一方面,此表达式非常无效:

#theObject.Get_Item(row).Get_Properties()。Get_Item(col).Get_Count()-1#

以第一部分为例,代码使Get_Item(row)使CF能够针对#columnListloop的每次迭代检索行及其属性;最重要的是,我们要在columnlist的每次迭代中执行两次TWICE(一次用于循环,另一次用于内部cfset)。如果我们考虑一下,它只需要为外部循环的每次迭代检索行(从#sfstart到#cfend)。因此,用伪代码执行此操作:

for each row between start and end
  
  
    cfset props = #theobject.get_item(row).get_properties()#
    
    for each col in #columnlist#
    
    
      cfset currentcol = #props.getitem(col)#
      
      cfset count = #currentcol.getcount() - 1#
      
      foreach item from 0 to #count#
      
      
        cfset #currentcol.getItem(item)# etc...

有道理?每次我们进入循环时,都将在该作用域(或者子作用域)中将重用的对象缓存在变量中。这意味着我们每次在列循环的迭代中只获取一次列对象。外部作用域中定义的所有变量都可以在内部作用域中使用,正如我们在上面所做的操作中所看到的那样。我知道它很想从以前的行中剪切和粘贴,但是事实并非如此。最后只会伤害你。

希望这可以帮助,

爱信

回答

此外,在每个循环中使用cftry块可能会大大降低此速度。除非我们期望单个行失败(并且我们需要从这一点继续),否则我建议对整个过程使用一个try / catch块。尝试/捕获是一项昂贵的操作。

回答

内循环的项目列表有多大?

如果存在大量项目,则切换到阵列可能会更快。

我已经与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>

回答

我认为我们想停止在循环内进行大量评估,而是使用变量来保存计数,指向col对象的指针并保存pipe-delim字符串,直到准备好提交给查询对象。如果我正确地完成了重构,那么使用以下代码应该会注意到一个改进:

<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>