Вопрос

Как я могу оптимизировать следующий код, который в настоящее время занимает более 2 минут для извлечения и перебора более 800 записей из пула, состоящего из более чем 100 тысяч записей, возвращая 6 полей на запись (добавляет примерно 20 секунд на каждое дополнительное поле):

<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>
Это было полезно?

Решение

Насколько велик список элементов для внутреннего цикла?

Переключение на массив мощь быть быстрее, если имеется значительно большое количество элементов.

Я реализовал это вместе с предложениями 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>

Другие советы

Давно я не касался CF, но могу дать некоторые подсказки в псевдокоде.Во-первых, это выражение крайне неэффективно:

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

Возьмем, к примеру, первую часть: Get_Item(row) — ваш код заставляет CF извлекать строку и ее свойства для каждой итерации цикла #columnList#;и в довершение всего, вы делаете это ДВАЖДЫ за итерацию списка столбцов (один раз для цикла и еще раз для внутреннего cfset).Если подумать, ему нужно только получить строку для каждой итерации внешнего цикла (от #sfstart# до #cfend).Итак, в псевдокоде сделайте следующее:

для каждой строки между началом и концом

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

для каждого столбца в #columnlist#

cfset currentcol = #props.getitem(col)#

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

по каждому элементу от 0 до #count#

cfset #currentcol.getItem(item)# и т.д...

Имеет смысл?Каждый раз, когда вы входите в цикл, кэшируйте объекты, которые будут повторно использоваться в этой области (или дочерних областях), в переменной.Это означает, что вы захватываете объект столбца только один раз за итерацию цикла столбца.Все переменные, определенные во внешних областях, доступны во внутренних, как вы можете видеть из того, что я сделал выше.Я знаю, что заманчиво вырезать и вставлять предыдущие строки, но не делайте этого.В конце концов это только навредит тебе.

надеюсь это поможет,

Ойсин

Кроме того, использование блока cftry в каждом цикле, вероятно, немного замедлит этот процесс.Если вы не ожидаете, что отдельные строки потерпят неудачу (и вам нужно продолжить с этого момента), я бы предложил один блок try/catch для всего процесса.Try/catch — дорогостоящая операция.

Я думаю, вам стоит прекратить выполнять так много вычислений внутри ваших циклов и вместо этого использовать переменные для хранения счетчиков, указателей на объект col и для хранения строки разделения канала до тех пор, пока вы не будете готовы передать объект запроса. .Если я выполнил рефакторинг правильно, вы заметите улучшение, если воспользуетесь приведенным ниже кодом:

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top