Pregunta

¿Cómo puedo optimizar el siguiente código, que actualmente tarda más de 2 minutos en recuperar y recorrer más de 800 registros de un grupo de más de 100.000 registros, devolviendo 6 campos por registro (agrega aproximadamente 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>
¿Fue útil?

Solución

¿Qué tamaño tiene la lista de elementos del bucle interno?

Cambiar a una matriz podría será más rápido si hay una cantidad significativamente grande de elementos.

He implementado esto junto con las sugerencias 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>

Otros consejos

Ha pasado mucho tiempo desde que toqué la FQ, pero puedo dar algunas pistas en pseudocódigo.Por un lado, esta expresión es extremadamente ineficiente:

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

Tome la primera parte, por ejemplo, Get_Item(row): su código hace que CF recupere la fila y sus propiedades para cada iteración del bucle #columnList#;y para colmo, lo estás haciendo DOS VECES por iteración de la lista de columnas (una vez para el bucle y otra vez para el cfset interno).Si lo piensas bien, solo necesita recuperar la fila para cada iteración del bucle externo (desde #sfstart# hasta #cfend).Entonces, en pseudocódigo haz esto:

para cada fila entre el inicio y el final

cfset props = #elobjeto.get_item(fila).get_properties()#

para cada columna en #columnlist#

cfset colactual = #props.getitem(col)#

recuento de cfset = #currentcol.getcount() - 1#

para cada elemento de 0 a #count#

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

¿Tener sentido?Cada vez que ingresa a un bucle, almacena en caché los objetos que se reutilizarán en ese ámbito (o ámbitos secundarios) en una variable.Eso significa que solo está tomando el objeto de la columna una vez por iteración del bucle de la columna.Todas las variables definidas en ámbitos externos están disponibles en los ámbitos internos, como puede ver en lo que hice anteriormente.Sé que es tentador cortar y pegar líneas anteriores, pero no lo hagas.Al final sólo te duele.

espero que esto ayude,

Oisín

Además, el uso de un bloque cftry en cada bucle probablemente ralentice esto bastante.A menos que espere que fallen las filas individuales (y necesite continuar desde ese punto), sugeriría un único bloque try/catch para todo el proceso.Probar/capturar es una operación costosa.

Creo que querrías dejar de hacer tantas evaluaciones dentro de tus bucles y en su lugar usar variables para contener recuentos, punteros al objeto col y mantener tu cadena de delimitación de tubería hasta que estés listo para comprometerte con el objeto de consulta. .Si realicé la refactorización correctamente, deberías notar una mejora si usas el siguiente código:

<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 bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top