Domanda

Come posso ottimizzare il seguente codice, che attualmente impiega più di 2 minuti per recuperare e scorrere oltre 800 record da un pool di oltre 100.000 record, restituendo 6 campi per record (aggiunge circa 20 secondi per campo aggiuntivo):

<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>
È stato utile?

Soluzione

Quanto è lungo l'elenco di elementi per il ciclo interno?

Passaggio a un array Potrebbe essere più veloce se è presente un numero notevolmente elevato di elementi.

L'ho implementato insieme ai suggerimenti di 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>

Altri suggerimenti

È passato molto tempo dall'ultima volta che ho toccato CF, ma posso dare alcuni suggerimenti in pseudo-codice.Per prima cosa, questa espressione è estremamente inefficace:

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

Prendi la prima parte, ad esempio, Get_Item(row): il tuo codice fa sì che CF recuperi la riga e le sue proprietà per ogni iterazione del ciclo #columnList#;e per finire, lo stai facendo DUE VOLTE per iterazione di columnlist (una volta per il ciclo e di nuovo per il cfset interno).Se ci pensi, deve solo recuperare la riga per ogni iterazione del ciclo esterno (da #sfstart# a #cfend).Quindi, in pseudo-codice fai questo:

per ogni riga tra l'inizio e la fine

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

per ogni colonna in #columnlist#

cfset currentcol = #props.getitem(col)#

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

per ogni elemento da 0 a #count#

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

Ha senso?Ogni volta che si entra in un ciclo, vengono memorizzati nella cache gli oggetti che verranno riutilizzati in quell'ambito (o negli ambiti figlio) in una variabile.Ciò significa che stai catturando l'oggetto colonna solo una volta per iterazione del ciclo della colonna.Tutte le variabili definite negli ambiti esterni sono disponibili negli ambiti interni, come puoi vedere in quello che ho fatto sopra.So che è forte la tentazione di tagliare e incollare dalle righe precedenti, ma non farlo.Alla fine ti fa solo male.

spero che questo ti aiuti,

Oisin

Inoltre, l'utilizzo di un blocco cftry in ogni ciclo probabilmente rallenta un po' il tutto.A meno che non ti aspetti che singole righe falliscano (e devi continuare da quel punto), suggerirei un singolo blocco try/catch per l'intero processo.Provare/catturare è un'operazione costosa.

Penserei che vorresti smettere di fare così tante valutazioni all'interno dei tuoi cicli e utilizzare invece variabili per contenere conteggi, puntatori all'oggetto col e per mantenere la stringa pipe-delim finché non sei pronto per impegnarti nell'oggetto query .Se ho eseguito correttamente il refactoring, dovresti notare un miglioramento se usi il codice seguente:

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

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top