如何优化以下代码,目前需要 2 分钟以上的时间从超过 100K 记录的池中检索和循环 800 多条记录,每条记录返回 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>
有帮助吗?

解决方案

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

切换到数组 可能 如果有大量项目,速度会更快。

我已经按照 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# 循环的每次迭代检索行及其属性;最重要的是,每次列列表迭代您都会执行两次(一次 for 循环,另一次针对内部 cfset)。如果您考虑一下,它只需要检索外循环每次迭代的行(从#sfstart#到#cfend)。因此,在伪代码中执行以下操作:

对于开始和结束之间的每一行

cfset props = #theobject.get_item(row).get_properties()#

对于#columnlist#中的每个列

cfset currentcol = #props.getitem(col)#

cfset 计数 = #currentcol.getcount() - 1#

foreach 项目从 0 到 #count#

cfset #currentcol.getItem(item)# 等...

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

希望这可以帮助,

奥辛

此外,在每个循环中使用 cftry 块可能会大大减慢速度。除非您预计个别行会失败(并且您需要从该点继续),否则我建议整个过程使用单个 try/catch 块。Try/catch 是一项昂贵的操作。

我认为您希望停止在循环内进行如此多的评估,而是使用变量来保存计数、指向 col 对象的指针并保存管道 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>

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top