Как ускорить получение данных из .NET AD в ColdFusion? - PullRequest
2 голосов
/ 17 сентября 2008

Как я могу оптимизировать следующий код, который в настоящее время занимает более 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>

Ответы [ 4 ]

2 голосов
/ 17 сентября 2008

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

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

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

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

# theObject.Get_Item (строка) .Get_Properties () Get_Item (COL) .Get_Count () -. 1 #

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

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

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

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

cfset currentcol = # props.getitem (col) #

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

элемент foreach от 0 до # count #

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

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

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

Oisin

1 голос
/ 17 сентября 2008

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

0 голосов
/ 17 сентября 2008

Я бы подумал, что вы захотите прекратить делать так много вычислений внутри ваших циклов и вместо этого использовать переменные для хранения счетчиков, указателей на объект 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>

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...