Question

Comment puis-je optimiser le code suivant, qui nécessite actuellement plus de 2 minutes pour extraire et mettre en boucle plus de 800 enregistrements d'un pool de plus de 100 000 enregistrements, en renvoyant 6 champs par enregistrement (ajoute environ 20 secondes par champ supplémentaire):

<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>
Était-ce utile?

La solution

Quelle est la taille de la liste d'éléments pour la boucle interne?

Le passage à un tableau peut être plus rapide si le nombre d'éléments est considérable.

J'ai implémenté cela parallèlement aux suggestions 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>

Autres conseils

Cela fait longtemps que je n'ai pas touché CF, mais je peux donner quelques indices en pseudo-code. D'une part, cette expression est extrêmement inefficace:

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

Prenez la première partie, par exemple, Get_Item (row) - votre code amène CF à récupérer la ligne et ses propriétés pour chaque itération de la boucle # columnList #; et pour couronner le tout, vous faites cela deux fois par itération de liste de colonnes (une fois pour boucle et encore pour le cfset interne). Si vous y réfléchissez, il suffit de récupérer la ligne pour chaque itération de la boucle externe (de # sfstart # à #cfend). Donc, en pseudo-code, faites ceci:

  

pour chaque ligne entre début et fin

     
    

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

         

pour chaque colonne dans #columnlist #

         
      

cfset currentcol = # props.getitem (col) #

             

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

             

foreach item de 0 à #count #

             
        

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

      
    
  

Avez-vous du sens? Chaque fois que vous entrez dans une boucle, mettez en cache les objets qui seront réutilisés dans cette étendue (ou étendues enfants) dans une variable. Cela signifie que vous ne récupérez l'objet de colonne qu'une fois par itération de la boucle de colonne. Toutes les variables définies dans les étendues externes sont disponibles dans les étendues internes, comme vous pouvez le voir dans ce que j'ai fait ci-dessus. Je sais que c'est tentant de couper et coller des lignes précédentes, mais ne le faites pas. Cela ne fait que vous faire mal à la fin.

espérons que cela aide,

Oisin

De plus, l’utilisation d’un bloc cftry dans chaque boucle ralentit probablement beaucoup cette opération. À moins que vous ne vous attendiez à ce que des lignes individuelles échouent (et que vous deviez continuer à partir de ce point), je suggérerais un seul bloc try / catch pour l'ensemble du processus. Try / catch est une opération coûteuse.

Je penserais que vous voudriez arrêter de faire autant d’évaluations à l’intérieur de vos boucles et utiliser plutôt des variables pour conserver des comptes, des pointeurs vers l’objet col et pour conserver votre chaîne pipe-delim jusqu’à ce que vous soyez prêt à vous engager. l'objet de requête. Si j'ai correctement refactoré, vous devriez remarquer une amélioration si vous utilisez le code ci-dessous:

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

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top