2015-09-06 1 views
1

Я читаю the article, объясняя алгоритм вложенного цикла и я точно не понимаю фактический принцип работы вложенных выборок. Вот пример, приведенный в статье:Понимание вложенного выбора для ORM

Примеры поиска сотрудников, чьи фамилии начинаются с «WIN» и извлекает все ПРОДАЖ для этих сотрудников.

И запросы, представляющие вложенных циклов таковы:

select employees0_.subsidiary_id as subsidiary1_0_ 
     -- MORE COLUMNS 
from employees employees0_ 
where upper(employees0_.last_name) like ?; 

select sales0_.subsidiary_id as subsidiary4_0_1_ 
     -- MORE COLUMNS 
from sales sales0_ 
where sales0_.subsidiary_id=? 
    and sales0_.employee_id=?; 

select sales0_.subsidiary_id as subsidiary4_0_1_ 
     -- MORE COLUMNS 
from sales sales0_ 
where sales0_.subsidiary_id=? 
    and sales0_.employee_id=?; 

Как вы можете видеть, два последних запросов совершенно одинаковы. Это то, что я смутил. Почему не просто генерировать первые два запроса недостаточно? Почему мы должны генерировать третий?

+1

Вы попробовали 'Hibernate JPA 3.6.0' самостоятельно для создания запросов? Похоже, опечатка для копирования/вставки doble. –

ответ

1

Имейте в виду, что приведенный вами код является ссылкой на пример статьи не сделать – анти-шаблон.

Таким образом, запросы параметризуются и, следовательно, фактически не идентичны. Два начальных символа ? в каждом запросе будут заменены на другое значение для subsidiary_id на каждой итерации цикла for.

0

Нет необходимости генерировать третий запрос. Если вы пишете SQL-запросы вручную, вы можете загрузить все продажи для всех извлеченных сотрудников в виде одного запроса. Но «N + 1 запрос» возникает антишаблон когда программный код выглядит как в статье:

for (Employees e: emp) { 
    // process Employee 
    for (Sales s: e.getSales()) { 
    // process sale for Employee 
    } 
} 

в этом коде e.getSales() метод загружает данные для одного сотрудника. Этот метод не располагает достаточной информацией для загрузки данных о продажах для всех других сотрудников, поскольку ORM не имеет полного списка сотрудников, для которых необходимо загрузить данные о продажах. Таким образом, ORM вынуждена загружать данные продаж каждого сотрудника в отдельный запрос.

Некоторые ORM могут автоматически устранить проблему «N + 1 запрос». Например, в PonyORM (написанный на Python) код из статьи будет выглядеть следующим образом:

# the first query loads all necessary employees 
employees = select(e for e in Employee if e.lastName.startswith('WIN')) 

for e in employees: 
    # process Employee 
    for sale in e.sales: 
     # process sale for Employee 

Когда программа начинает цикл по запросу работника, PonyORM загружает все необходимые сотрудники сразу. Когда запрашиваются элементы продаж для первого сотрудника, PonyORM загружает его только для этого сотрудника (поскольку ORM не знает нашего намерения и предполагает, что, возможно, нам нужны данные о продажах только для первого сотрудника). Но когда запрашиваются данные о продажах второго сотрудника, PonyORM замечает анти-шаблон «N + 1 запрос», видит, что у нас есть N объектов сотрудников, загруженных в память, и загружает продажи для всех остальных сотрудников в одном запросе. Такое поведение можно рассматривать как эвристику. Он может загружать некоторые дополнительные объекты продаж, если наш for -loop содержит операцию break. Но обычно эта эвристика приводит к повышению производительности, поскольку она может значительно сократить количество запросов. Как правило, не проблема загружать некоторые дополнительные данные, гораздо важнее уменьшить количество обращений к серверу.

 Смежные вопросы

  • Нет связанных вопросов^_^