Ускорить QoQ или альтернативный подход? - PullRequest
2 голосов
/ 05 мая 2011

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

В других частях этого приложения я иногда запускаю сотню QoQ для этих данных - обычно это результат рекурсивных вызовов функций.Тем не менее, хотя QoQ - отличная функция, она не слишком быстрая, и иногда загрузка страниц в плохой день может составлять от 3000 до 5000 мс.Это просто недостаточно быстро.

Могу ли я использовать какие-либо методы оптимизации, чтобы QoQ работал быстрее или, возможно, альтернативный метод?Я прочитал интересную статью Бена Наделя о функции Duplicate () - есть ли возможность использовать это, и если да, то как?

Я хотел бы услышать ваши мысли.

Небеспокоиться о сумасшедших предложениях, это личный проект, поэтому я готов рисковать.Я запускаю это на Railo, совместимом с CF8.

Большое спасибо, Майкл.

Ответы [ 3 ]

2 голосов
/ 05 мая 2011

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

Например:

<!--- build up index --->
<cfset structindex = {} />
<cfset fields = "first,last,company" />
<cfloop list="#fields#" index="field">
    <cfset key = "field:#field#,value:#q[field][currentrow]#" />
    <!--- initialize each key (instead of using stuctkeyexists) --->
    <cfloop query="q">
        <cfset structindex[key] = "" />
    </cfloop>
    <cfloop query="q">
        <!--- update each key with list of matching row indexes --->
        <cfset structindex[key] = listappend(structindex[key], currentrow) />
    </cfloop>
</cfloop>

<!--- save structindex to global variable --->

<!--- output rows matching index --->
<cfset key = "field:company,value:stackexchange" />
<cfoutput>
    <cfloop list="#structindex[key]#" index="row">
        #q.last[row]#, #q.first[row]# (#q.company[row]#)<br />
    </cfloop>
</cfoutput>

Если это не соответствует вашим потребностям, приведите несколько примеров операторов QoQ и количества записей в основном запросе.

1 голос
/ 06 мая 2011

Здесь есть два основных решения. Сначала вы можете сделать что-то в CF с записями вне QoQ. Я уже опубликовал свое предложение по этому вопросу. Другой - все делать в БД. Один из способов сделать это - использовать подзапрос в качестве временной таблицы. Вы даже можете сохранить оператор sql в глобальной переменной, а затем ссылаться на него в тех же местах, где вы в настоящее время используете QoQ, но делаете реальный запрос к базе данных. Это может звучать медленнее, чем одна поездка в БД, а затем много QoQ, но на самом деле это, вероятно, не так, если эффективно проиндексированы.

select *
from (
    #sqlstring#
) as tmp
where company = 'stackexchange'

Я фактически сделал это для системы со сложными критериями как к тем записям, к которым у пользователя должен быть доступ, так и к тому, что они могут фильтровать в этих записях. Использование этого подхода означает, что вы всегда знаете источник внутренних записей, а не пытаетесь убедиться, что каждый запрос выполняется правильно.

Edit: На самом деле безопаснее (и, как правило, более эффективно) использовать параметры запросов, когда это возможно. Я обнаружил, что это можно сделать, включив файл оператора SQL ...

select *
from (
    <cfinclude template="master_subquery.cfm" />
) as tmp
where company = 'stackexchange'
1 голос
/ 05 мая 2011

Во-первых, я бы посмотрел на время, затраченное на главный запрос.Если бы он мог быть кэширован в течение некоторого периода времени и занимал большую часть времени загрузки страницы, я бы его кешировал.

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

Я мог бы также рассмотреть написание некоторых хранимых процедур рекурсивного QoQ на сервере БД, который предназначен для быстрой обработки данныхи нарезать и кости эффективно.CF - нет - QoQ очень полезны, но не демоны скорости (как вы заметили).

Наконец, я бы посмотрел на прямые фильтры, а не использовал QoQ.Скорее, я бы просто запустил цикл над главным запросом в стандартном теге cfoutput и отфильтровал на лету.Это означает, что вы зацикливаетесь на главном запросе один раз, а не на основном запросе один раз и на результате запроса один раз.

...