2008-09-17 6 views
2

Wie kann ich optimieren den folgenden Code, der derzeit mehr als 2 Minuten dauert abrufen und Schleife durch 800+ Datensätze aus einem Pool von über 100 K Datensätze, Rückkehr 6 Felder pro Datensatz (ca. 20 Sekunden pro zusätzliches Feld ergänzt):Wie beschleunige ich den Datenabruf von .NET AD in ColdFusion?

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

Antwort

2

Wie groß ist die Liste der Elemente für die innere Schleife?

Wechseln zu einem Array könnte schneller sein, wenn es eine erhebliche Anzahl von Elementen gibt.

Ich habe dies neben X0n's Vorschläge implementiert ...

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

Okay, also habe ich das ausprobiert ... und ich sehe etwa 30% weniger Zeit für die Ausführung ... das scheint Senes zu machen, weil wir effektiv ein Drittel der Aufrufe für Artikel reduziert haben Singular. Ich bin auf jeden Fall an anderen Optimierungen interessiert, die Sie sich vorstellen können ... – Brian

2

Es ist eine lange Zeit her, seit ich CF berührt habe, aber ich kann einige Hinweise in Pseudocode geben. Zum einen ist dieser Ausdruck extrem ineffiziente:

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

Nehmen Sie den ersten Teil zum Beispiel Get_Item (. row) - Ihr Code veranlasst CF, die Zeile und ihre Eigenschaften für jede Iteration der # columnList # loop abzurufen; Und um das Ganze zu übertreffen, machen Sie das ZWEIMAL pro Iteration der Spaltenliste (einmal für die Schleife und einmal für die innere cfset). Wenn Sie darüber nachdenken, muss nur die Zeile für jede Iteration der äußeren Schleife abgerufen werden (von # sfstart # nach #cfend). Also, in Pseudo-Code wie folgt vorgehen:

für jede Zeile zwischen Anfang und Ende

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

für jede Spalte in # column #

cfset currentcol = # props.getitem (col) #

cfset count = #current col.getcount() - 1 #

foreach Artikel von 0 bis # #

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

zählen

Sinn machen? Jedes Mal, wenn Sie eine Schleife eingeben, werden Objekte zwischengespeichert, die in diesem Bereich (oder untergeordneten Bereichen) in einer Variablen wiederverwendet werden. Das bedeutet, dass Sie das Spaltenobjekt nur einmal pro Iteration der Spaltenschleife erfassen. Alle in den äußeren Bereichen definierten Variablen sind in den inneren Bereichen verfügbar, wie Sie oben sehen können. Ich weiß, dass es verlockend ist, aus früheren Zeilen zu schneiden und einzufügen, aber tue es nicht. Es verletzt dich am Ende nur.

hoffe, das hilft,

Oisin

+0

Die Zählvariable/Caching ist nicht notwendig - CF die von/nach Werten für cfloop zwischengespeichert werden . (Obwohl nicht für eine Schleife Anweisung in cfscript) –

+0

hätte ich so gedacht, aber ich habe versucht, einen Punkt zu demonstrieren. – x0n

1

Zusätzlich verlangsamt ein cftry Block in jeder Schleife wahrscheinlich, dass diese ein wenig ganz nach unten. Wenn Sie nicht erwarten, dass einzelne Zeilen ausfallen (und Sie müssen von diesem Punkt aus fortfahren), würde ich einen einzelnen try/catch-Block für den gesamten Prozess vorschlagen. Try/Catch ist eine teure Operation.

+0

Ja, aber in diesem Fall erwarte ich schlechte oder fehlende Daten ... damit muss ich leben. Frage: Angesichts der anderen Vorschläge gehe ich davon aus, dass ich das umgehen könnte, indem ich den ItemCount am niedrigsten Scope – Brian

+0

erneut überprüfe, ich kann nicht für CF sprechen, aber in jeder anderen Sprache mit try/catch und Ausnahmen ist es nicht der Versuch/catch das ist teuer, es ist die Schaffung der Ausnahme. Dies liegt daran, dass eine Ausnahme eine Stack-Trace enthält - also eine Liste aller Methoden, die bis zu diesem Zeitpunkt aufgerufen wurden. – x0n

0

Ich würde denken, dass Sie zählt dabei so viele Bewertungen innerhalb von Loops stoppen wollen würde und stattdessen Variablen verwenden zu halten, Zeiger auf die Spalte Objekt und Ihr Rohr delim Zeichenfolge zu halten, bis du bist bereit, sich an das Abfrageobjekt zu binden. Wenn ich das Refactoring richtig gemacht haben, sollten Sie eine Verbesserung feststellen, wenn Sie den Code unten verwenden:

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

+0

Okay, also lass mich ein wenig verdauen ... Dieser Aufruf durch das Objekt ist nicht vergleichbar mit einem Array, sondern eher eine Reihe von Kettenanrufen? [schlägt auf die Stirn] Kein Wunder, dass es so schwer ist ... Ich werde diesen Code wieder durchspielen ... Ich werde in ungefähr einer Stunde einige Ergebnisse zurückbringen – Brian

+0

Ich denke, das ist korrekt, da du ein .NET-Objekt instanziierst Sie sollten in der Lage sein, eine Variable so einzustellen, dass sie auf ein Objekt weiter unten in der Kette zeigt, wodurch die Anzahl der Male reduziert wird, die Sie durch das erste Objekt graben müssen, besonders wenn Sie nur nach einer Anzahl von Objekten suchen. – kooshmoose

+0

Haben Sie gegen meine etwas andere Lösung verglichen? Ich bezweifle, dass Sie einen Leistungsunterschied sehen würden, aber es wäre interessant, einige Metriken über den Unterschied zwischen dem Speichern von Iterationen in einem Array und einem String zu erhalten. – kooshmoose