Mam obiekt usera z asocjacją 1:1 którą chciałbym sobie wciągać pojedynczym zapytaniem SQL JOIN. Próbuję User.includes(:stat).find(1) co robi dwa zapytania, próbuję dalej User.joins(:stat).find(1) i mam fajne zapytanie z JOIN ale nie potrafię dobrać się do JOINowanych z tabeli ‘stats’ danych, u.stat.costam robi mi kolejne zapytanie. Wiecie może jak to zrobić?
Zostaw .includes, bo zawsze będzie ci wykonywało dwa zapytania (nawet jeśli będziesz wyciągał nie jednego, a 20 userów) i jest generalnie lepszym nawykiem niż .joins
(JOIN jest często wolniejszy niż dwa konkretne zapytania do pojedynczych tabel, oraz np. sqlite nie wspiera JOINów)
[quote=Tomash]Zostaw .includes, bo zawsze będzie ci wykonywało dwa zapytania (nawet jeśli będziesz wyciągał nie jednego, a 20 userów) i jest generalnie lepszym nawykiem niż .joins
(JOIN jest często wolniejszy niż dwa konkretne zapytania do pojedynczych tabel, oraz np. sqlite nie wspiera JOINów)[/quote]
dzięki za odpowiedź, IMO jeśli masz właściwe indeksy JOIN zawsze będzie szybszy (myślę o MySQL) - odpadnie co najmniej czas na komunikację/parsowanie po stronie bazy danych i wykonanie kodu po stronie aplikacji. Anyway, czy to oznacza, że się nie da?
0_o?
[quote=pink][quote=Tomash]Zostaw .includes, bo zawsze będzie ci wykonywało dwa zapytania (nawet jeśli będziesz wyciągał nie jednego, a 20 userów) i jest generalnie lepszym nawykiem niż .joins
(JOIN jest często wolniejszy niż dwa konkretne zapytania do pojedynczych tabel, oraz np. sqlite nie wspiera JOINów)[/quote]
dzięki za odpowiedź, IMO jeśli masz właściwe indeksy JOIN zawsze będzie szybszy (myślę o MySQL) - odpadnie co najmniej czas na komunikację/parsowanie po stronie bazy danych i wykonanie kodu po stronie aplikacji. Anyway, czy to oznacza, że się nie da?[/quote]
No dobra, to inaczej, czy w takim razie dobrą praktyką jest wyciąganie sobie danych używając bezpośrednich zapytań i instancjonowanie obiektów z wyników? Na moje oko to wygląda na spory race-condition i nie wydaje się być poprawne, chyba że ActiveRecord robi jakąś magię.
To nawet nie jest bliskie prawdy.
Odpowiadając na pytanie zadane w wątku przez pinka:
u = User.joins(:stat).includes(:stat).find(0) # tu może być chyba joins(:stats), nie jestem pewien
u.stat
Powinno wykonać tylko 1 zapytanie, dość złożony join i przy dostępie do asocjacji nie będzie wykonane drugie. Nie mam tego jak teraz sprawdzić przy asocjacji has_one ale przy has_many/belongs_to działa świetnie.
To nawet nie jest bliskie prawdy.[/quote]
Gwoli ścisłości, wspiera podzbiór joinów – konkretnie tylko jeden typ. A Ty zanim się oburzysz może spojrzyj w oficjalną dokumentację?
http://www.sqlite.org/omitted.html
Active Record wspiera 2 sposóby preładowania obiektów.
a) stary, który robił dużego joina i samemu wszystkie kolumny odpowiednio aliasował
b) nowy, który korzysta z kilku zapytań by osiągnać odpowiedni efekt.
Stary tryb jest wciąż używany kiedy zapytanie o powiązane rekordy ma warunek, którego sprawdzenia wymaga czegoś z oryginalnych rekordów. Jesli nie ma takiej konieczności to railsy używaja nowego trybu. Można wymusić zastosowanie któregoś z nich.
Porównajcie sobie query generowane przez:
Post.includes(:comments)
Post.preload(:comments)
Post.eager_load(:comments)
http://api.rubyonrails.org/classes/ActiveRecord/Relation.html :
ASSOCIATION_METHODS = [:includes, :eager_load, :preload]