Edge Rails: Uma nova estratégia para o Eager Loading 6

Publicado por Carlos Brando em 02 de Fevereiro de 2008

219781763_29850fce52.jpg

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.

Trackbacks

Use este link para fazer o trackback do seu site.

Comentários

Deixe um comentário

  1. Lucas Húngaro Sab, 02 de Fev de 2008 21:52:35 PST

    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)

  2. Carlos Brando Dom, 03 de Fev de 2008 00:27:00 PST

    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.

  3. Ramon Soares Seg, 04 de Fev de 2008 11:00:33 PST

    acho que isso apenas se encaixa em consultas que retornam poucos dados. Imagina se o “SELECT * FROM “authors”” retorna 100 mil registros por exemplo.

  4. Carlos Brando Ter, 05 de Fev de 2008 12:38:57 PST

    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.

  5. otavio Qui, 07 de Fev de 2008 13:06:44 PST

    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).

  6. [...] Um problema dos ORM é volume de dados gerados, em alguns casos a performance é bastante prejudicada, mas a coisa vem mudando, o Rails por exemplo implementou uma mudança que elimina muito o volume de dados em cada consulta ao… [...]

Comentários