#ruby #datamapper
#ruby #datamapper
Вопрос:
DataMapper, похоже, генерирует крайне неоптимальные запросы для ассоциаций, которые используют таблицу объединения. Что я могу сделать, чтобы повысить производительность этих запросов? Обратите внимание, что он также генерирует те же запросы с неявной таблицей объединения ( :through => Resource
)
Вот моя настройка:
class Left
include DataMapper::Resource
property :id, Serial
has n, :joins
has n, :rights, :through => :joins
end
class Join
include DataMapper::Resource
belongs_to :left, :key => true
belongs_to :right, :key => true
end
class Right
include DataMapper::Resource
property :id, Serial
property :one, String
property :two, Integer
end
Теперь, допустим, у меня есть некоторые заполненные данные, и я хочу получить все права, связанные с левым объектом:
Left.first.rights
DataMapper выполняет следующий запрос:
SELECT rights.id, rights.one, rights.two FROM rights INNER JOIN joins ON rights.id = joins.right_id
INNER JOIN lefts ON joins.left_id = lefts.id
WHERE joins.left_id = 1
GROUP BY rights.id, rights.one, rights.two
ORDER BY rights.id
-
DataMapper генерирует совершенно ненужный
JOIN
(первый выделенный жирным шрифтом раздел). Я не доверяю своей СУБД (MySQL), чтобы она умела игнорировать это. В плане объяснения это отображается как «Использование индекса; Использование временного; Использование сортировки файлов», по крайней мере. -
Что случилось с
GROUP BY
? Здесь это также кажется совершенно ненужным — из-за составного ключа в таблице объединения у меня не может быть дубликатов. Кроме того, не будетGROUP BY rights.id
такого же эффекта? Или даже лучше,SELECT DISTINCT
Эти запросы выполняются чрезвычайно медленно (для таблиц с большим количеством свойств с обеих сторон), и я не уверен, как правильно индексировать таблицы для его поддержки.
Гораздо быстрее выполнять запросы из модели объединения: Join.all(:left => Left.first).rights
, хотя она выполняет два оператора:
SELECT right_id FROM joins WHERE left_id = 1
SELECT id, one, two FROM rights WHERE id = 1 ORDER BY id
Интересно, что Left.first.joins.rights
идет тем же маршрутом и выполняет два приведенных выше запроса.
Комментарии:
1. Ваш вопрос действительно «почему?» или, возможно, «как мне избежать этого»?
Ответ №1:
Как насчет удаления определения класса Join и определения Left как:
class Left
include DataMapper::Resource
property :id, Serial
has n, :rights, :through => Resource
end
Поверьте DM, это создает хорошее сопоставление для вас.