2

如何优化以下代码,目前需要 2 分钟以上的时间从超过 10 万条记录的池中检索和遍历 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>
4

4 回答 4

2

很久没接触CF了,不过可以用伪代码给出一些提示。一方面,这个表达式非常低效:

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

以第一部分为例,Get_Item(row) - 您的代码使 CF 为 #columnList# 循环的每次迭代检索行及其属性;最重要的是,您在 columnlist 的每次迭代中都执行 TWICE(一次 for 循环,再次用于内部 cfset)。如果您考虑一下,它只需要为外部循环的每次迭代(从#sfstart# 到#cfend)检索行。所以,在伪代码中这样做:

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

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

对于#columnlist# 中的每个列

cfset currentcol = #props.getitem(col)#

cfset count = #currentcol.getcount() - 1#

foreach 项目从 0 到 #count#

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

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

希望这可以帮助,

奥辛

于 2008-09-17T16:32:39.580 回答
2

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

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

我已经与 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>
于 2008-09-17T18:01:25.030 回答
1

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

于 2008-09-17T17:57:35.663 回答
0

我认为您不想在循环内进行如此多的评估,而是使用变量来保存计数、指向 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>

于 2008-09-17T18:05:14.693 回答