Rails 3 добавляет имя базы данных в таблицу, включает в себя по умолчанию загружаемую нагрузку
Источники:
Мой проект движется к созданию нескольких баз данных (в настоящее время на одном сервере), и я хотел бы иметь возможность соединяться между этими базами данных. Для этого мне нужно добавить имя базы данных в префикс таблицы следующим образом:
class FirstBase < ActiveRecord::Base
def self.table_name_prefix
"DBNAME.t_"
end
establish_connection :firstdb
end
class User < FirstBase
has_many :user_roles
end
class UserRole < FirstBase
belongs_to :user
end
Добавление префикса имен таблиц, похоже, влияет на поведение по умолчанию, включенное в один и тот же запрос, даже в пределах одной базы данных. Рассмотрим User.includes(:user_roles).first
Без префикса имени таблицы:
Загрузка пользователя (67.1ms) SELECT t_users
. * FROM t_users
LIMIT 1 UserRole Load (84.5ms) SELECT t_user_roles
. * FROM t_user_roles
ГДЕ t_user_roles
. user_id
IN (1)
С префиксом имени таблицы:
SQL (76.8ms) SELECT DISTINCT DBNAME
. t_users
.id FROM DBNAME
. t_users
LEFT OUTER JOIN DBNAME
. t_user_roles
ВКЛ DBNAME
. t_user_roles
. user_id
= DBNAME
. t_users
. id
LIMIT 1
SQL (66.4ms) SELECT DBNAME
. t_users
. id
AS t0_r0, DBNAME
. t_users
. email
AS t0_r1, DBNAME
. t_user_roles
. id
AS t1_r0, DBNAME
. t_user_roles
. user_id
AS t1_r1 FROM DBNAME
. t_users
LEFT OUTER JOIN DBNAME
. t_user_roles
ВКЛ DBNAME
. t_user_roles
. user_id
= DBNAME
. t_users
. id
WHERE DBNAME
. t_users
. id
IN (1)
Другими словами, поведение по умолчанию для входящих вызовов изменилось с предварительной загрузки на загружаемую нагрузку.
Кто-нибудь знает, почему меняется поведение по умолчанию? Должно быть что-то о добавлении имени базы данных, которое заставляет Rails думать, что мы должны загружать загрузку, но я не понимаю, почему. Я также удивлен, увидев это, так как считаю, что добавить имя базы данных не так уж и необычно. Я могу скорректировать это в нашей базе кода, изменив все включенные в preload, но я хотел бы понять, что здесь происходит. Есть ли способ изменить поведение по умолчанию?
Ответы
Ответ 1
Проблема заключается в том, что table_name_prefix
вводит период. Это смущает логику, которая пытается определить, должна ли она загружаться или загружаться. Это ошибка Rails 3 и была разрешена в Rails 4. Если вам нужно определенное поведение в Rails 3, вам нужно явно указать preload
или eager_load
, как вы указали в своем вопросе.
В ActiveRecord:: Relation, exec_queries
вызывает eager_loading?
, чтобы решить, нужна ли ему загрузка. Это вызывает references_eager_loaded_tables?
, который использует tables_in_string
, чтобы попытаться найти имена таблиц в SQL-запросе, которые не являются частью объединенных таблиц:
# ActiveRecord::Relation#references_eager_loaded_tables?
(tables_in_string(to_sql) - joined_tables).any?
Метод tables_in_string
был ошибочным, поскольку он не всегда правильно разбирал SQL. Этот код можно использовать для просмотра того, что он считает именами таблиц в SQL-запросе:
relation = User.includes(:user_roles)
relation.send(:tables_in_string, relation.to_sql)
С префиксом имени таблицы DBNAME.t_
это даст ["DBNAME", "t_users"]
как имена таблиц, что неверно. Он должен дать ["DBNAME.t_users"]
.
Аналогичная проблема была зафиксирована в изменении запроса ActiveRecord, когда точка/период находится в значении условия. Это привело к изменениям в ActiveRecord:: Relation, которые отошли от использования tables_in_string
при принятии решения о предварительной загрузке или загрузке.