Оптимизация Rails для Oracle - Модели и SQL-запросы
ОГЛАВЛЕНИЕ
Модели и SQL-запросы
Теперь взглянем на некоторые из запросов, которые сгенерированы ActiveRecord, и это сделалось простым благодаря тому, что во время нахождения в режиме разработки система Rails записывает в журнал все запросы, которые она выполняет. Таким образом, можно ознакомиться с поведением инфраструктуры и получить глубокое понимание того, что должно делать инструментальное средство.
Я нахожу, что глубокое понимание, как именно код инфраструктуры собирается транслировать высокоуровневые запросы в фактические операторы SQL, является необходимым шагом при работе с мощными инфрастуктурами, которые выполняют сложные взаимодействия с данными. Вы получите лучшее понимание Rails-идиом, которые должны использоваться, и того, как написать более эффективный код.
Один из самых распространенных способов получения данных моделирования - это поиск объекта по его идентификатору (id):
emp = Employee.find(202)
Он дает запись служащего с id = 202. Просматривая development.log (журнал разработки), мы сможем увидеть выполняемые запросы:
Employee Columns (0.120000)
select column_name as name, data_type as sql_type, data_default, nullable,
decode(data_type, 'NUMBER', data_precision,
'FLOAT', data_precision,
'VARCHAR2', data_length,
null) as limit,
decode(data_type, 'NUMBER', data_scale, null) as scale
from all_tab_columns
where owner = 'RAILS'
and table_name = 'EMPLOYEES'
order by column_id
Employee Load (0.070000) SELECT * FROM employees WHERE (employees.id = 202)
Первый запрос выполняется после того, как будет в первый раз загружен класс моделей, чтобы вытянуть столбцы из таблицы служащего, позволяя системе динамически генерировать необходимые методы для модели, основываясь на структуре базы данных. (Это одна из тех опций, которые делают разработку в среде Rails действительно быстрой!). Имейте в виду, что в процессе выполнения своих действий при эксплуатации сервера в режиме разработки, вы увидите этот запрос многократно повторенным, так как модели перезагружаются при каждом запросе из браузера. Это делает сервер более медлительным, но позволяет получать обновления структур базы данных без перезапуска сервера.
Второй запрос получает из таблицы служащих данные для служащего, id которого равен 202.
Другими примерами моделей могут быть следующие (все примеры представляют фактические запросы, выполнявшиеся к базе данных):
Для заданного служащего получите менеджера его отдела.
mgr = emp.department.manager
SELECT * FROM departments WHERE (departments.id = 20)
SELECT * FROM employees WHERE (employees.id = 201)
Для заданного служащего получите всех его коллег из того же самого отдела.
emps = emp.department.employees
SELECT * FROM employees WHERE (employees.department_id = 20)
mgr.managed_employees
SELECT * FROM employees WHERE (employees.manager_id = 201)
Вы можете использовать опцию include, чтобы в одном запросе получить от сервера объекты, которые имеют некоторые отношения с нашим объектом:
emp = Employee.find(202, :include=>[:department,:manager])
emp.department
emp.manager
SELECT employees.id AS t0_r0, employees.commission AS t0_r1, employees.job_id AS t0_r2,
employees.manager_id AS t0_r3,employees.salary AS t0_r4, employees.hire_date AS t0_r5,
employees.phone_number AS t0_r6, employees.department_id AS t0_r7,
employees.first_name AS t0_r8, employees.last_name AS t0_r9, employees.email AS t0_r10,
departments.id AS t1_r0, departments.name AS t1_r1, departments.manager_id AS t1_r2,
departments.location_id AS t1_r3, managers_employees.id AS t2_r0,
managers_employees.commission AS t2_r1, managers_employees.job_id AS t2_r2,
managers_employees.manager_id AS t2_r3, managers_employees.salary AS t2_r4,
managers_employees.hire_date AS t2_r5, managers_employees.phone_number AS t2_r6,
managers_employees.department_id AS t2_r7, managers_employees.first_name AS t2_r8,
managers_employees.last_name AS t2_r9,
managers_employees.email AS t2_r10 FROM employees LEFT OUTER JOIN departments
ON departments.id = employees.department_id LEFT OUTER JOIN employees managers_employees
ON managers_employees.id = employees.manager_id WHERE (employees.id = 202)
Это действительно удобно и эффективно при работе с объектами, ведущими себя как контейнеры для наборов других элементов, поскольку позволяет не обращаться к базе данных с запросом для каждой строки, с которой вы желаете манипулировать.
Вот еще один пример:
job = Job.find(id,:include=>:employees)
job.employees
SELECT jobs.id AS t0_r0, jobs.job_title AS t0_r1, jobs.min_salary AS t0_r2,
jobs.max_salary AS t0_r3, employees.id AS t1_r0, employees.commission AS t1_r1,
employees.job_id AS t1_r2, employees.manager_id AS t1_r3, employees.salary AS t1_r4,
employees.hire_date AS t1_r5, employees.phone_number AS t1_r6,
employees.department_id AS t1_r7, employees.first_name AS t1_r8,
employees.last_name AS t1_r9, employees.email AS t1_r10 FROM jobs LEFT OUTER JOIN employees
ON employees.job_id = jobs.id WHERE (jobs.id = 7)
Одна из целей этой статьи состоит в том, чтобы показать новые параметры конфигурирования, впервые появившиеся в выпуске 1.2 системы Rails, которые могут помочь в настройке производительности вашего приложения, там где это связано с базой данных. Но прежде чем углубиться в эти вопросы, позвольте мне объяснить, как в настоящее время Rails строит фактически используемый код SQL.