
Para explicar esta nova funcionalidade vou precisar mostrar na prática. Vamos pegar como exemplo o código abaixo:
Author.find(:all, :include => [:posts, :comments])
Estou fazendo uma pesquisa na tabela authors, mas incluindo na minha query as tabelas posts e comments, relacionado-as pela coluna author_id. Para entender melhor veja a query gerada pelo Rails:
SELECT
authors."id" AS t0_r0,
authors."created_at" AS t0_r1,
authors."updated_at" AS t0_r2,
posts."id" AS t1_r0,
posts."author_id" AS t1_r1,
posts."created_at" AS t1_r2,
posts."updated_at" AS t1_r3,
comments."id" AS t2_r0,
comments."author_id" AS t2_r1,
comments."created_at" AS t2_r2,
comments."updated_at" AS t2_r3
FROM
authors
LEFT OUTER JOIN posts ON posts.author_id = authors.id
LEFT OUTER JOIN comments ON comments.author_id = authors.id
Uma única query SQL foi criada contendo joins entre as tabelas authors, posts e comments. Chamamos isto de produto cartesiano.
Acontece que isto nem sempre é performático, por isto foi alterado. Para a nova versão do Rails ao executar a mesma pesquisa na classe Author, o Rails usará uma outra estratégia para recuperar os dados das três tabelas. Ao invés de usar apenas uma query com todas as tabelas relacionadas, ele usará três querys menores, uma para cada tabela. Veja o resultado no log, após executar o mesmo código acima nesta nova versão Edge Rails:
SELECT * FROM "authors"
SELECT posts.* FROM "posts" WHERE (posts.author_id IN (1))
SELECT comments.* FROM "comments" WHERE (comments.author_id IN (1))
Na “maioria” dos casos executar três querys simples é mais rápido que executar uma única query gigante.
Pois é, vi essa mudança no Rails Envy Podcast dessa semana e fiquei meio em dúvida, pois sempre nos ensinam que o produto cartesiano é mais eficiente.
Então vi alguns benchmarks dessa mudança e parece que a realidade realmente é diferente da teoria (na maioria dos casos… :P)
Na verdade Lucas, não é em todo caso que querys soltas serão mais eficientes, mas como na maioria das vezes isto é verdade, então acho melhor o método assim mesmo.
acho que isso apenas se encaixa em consultas que retornam poucos dados. Imagina se o “SELECT * FROM Âauthors” retorna 100 mil registros por exemplo.
Hmm… uma query que retorne 100.000 registros com certeza terá problemas de performance nas duas formas. Mas ainda acho que a segunda forma será mais rápida neste caso. Não sei.
Já tinha visto isso e me pareceu uma grande (e simples) idéia. No trac do mesmo (http://dev.rubyonrails.org/ticket/9640) senti falta de 2 coisas: não vi benchmarks em outro banco de dados que não o mysql (eles não informam, mas presumo ser mysql) e não vi benchmarks muito completos (que mostrem qual o tamanho das tabelas acessadas).