Pergunta

Como posso otimizar o código a seguir, que atualmente leva mais de 2 minutos para recuperar e percorrer mais de 800 registros de um grupo de mais de 100 mil registros, retornando 6 campos por registro (adiciona cerca de 20 segundos por campo adicional):

<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>
Foi útil?

Solução

Qual o tamanho da lista de itens para o loop interno?

Mudar para um array pode ser mais rápido se houver um número significativamente grande de itens.

Eu tenho implementado este ao lado sugestões de 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>

Outras dicas

Tem sido um longo tempo desde que eu toquei CF, mas eu posso dar algumas dicas em pseudo-código. Por um lado, esta expressão é extremamente ineficiente:

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

Tome a primeira parte, por exemplo, Get_Item (linha) - o seu código faz com que CF para ir recuperar a linha e suas propriedades para cada iteração do loop # ColumnList #; e ao início de tudo, você está fazendo isso duas vezes por iteração de ColumnList (uma vez por ciclo e novamente para o cfset interior). Se você pensar sobre isso, ele só precisa recuperar a linha para cada iteração do loop externo (de # sfstart # para #cfend). Assim, em pseudo-código de fazer isso:

para cada linha entre o início eo fim

cfset adereços = # theobject.get_item (linha) .get_properties () #

para cada col no #columnlist #

cfset currentcol = # props.getitem (col) #

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

item de foreach de 0 a #count #

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

sentido FAZER? Toda vez que você entra em um loop, cache de objetos que serão reutilizados nesse âmbito (ou criança escopos) em uma variável. Isso significa que você está apenas pegando o objeto coluna uma vez por iteração do loop coluna. Todas as variáveis ??definidas em escopos externos estão disponíveis nos âmbitos internos, como você pode ver no que eu fiz acima. Eu sei que é tentador para cortar e colar a partir de linhas anteriores, mas não o fazem. Só dói-lo no final.

espero que isso ajude,

Oisin

Além disso, usando um bloco CFTRY em cada ciclo é provável retardar esse baixo um pouco. A menos que você está esperando linhas individuais a falhar (e você precisa de continuar a partir desse ponto), gostaria de sugerir um bloco try / catch único para todo o processo. Try / catch é uma operação cara.

Gostaria de pensar que você iria querer parar de fazer tantas avaliações dentro de seus loops e em vez disso usar variáveis ??para contagem de espera, ponteiros para o objeto col e para manter a sua cadeia de pipe-delim até que esteja pronto para comprometer-se o objeto de consulta. Se eu fiz a refatoração corretamente, você deve observar uma melhoria se você usar o código abaixo:

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

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top