DEV Community

Débora Fernandes
Débora Fernandes

Posted on • Originally published at Medium on

Sequel para ActiveRecord heavy-users

Uso apenas o ActiveRecord em minhas aplicações”

“Já tive problemas com features simples de desenvolver que geraram problemas em produção por consultar / escrever em tabelas gigantes”

Se alguma das afirmações acima for verdadeira para você, quero compartilhar com você, em especial se trabalha com Rails e usa exclusivamente o ActiveRecord, um modo alternativo de se comunicar com o banco de dados.

Assim, você terá mais opções quando precisar implementar nossas features que lidarão com grandes massas de dados.

O que é o SEQUEL?

Se nunca ouviu falar de Sequel, essa gem é até hoje a menor das libs de banco de dados para o Ruby em termos de tamanho de código e é também a que faz o load mais rápido na inicialização da sua APP, já que carrega apenas o CORE com as funcionalidades básicas para comunicação com o banco!

De acordo com suas necessidades, você pode adicionar funcionalidades adicionais via plugins, sendo que cada plugin corresponde a um único arquivo incluso na gem, que é carregado APENAS quando o plugin é requerido.

É isso que o torna mais rápido num comparativo com outros ORM’s.

Em uma classe limpa por exemplo, apenas realizando conexão com o banco, o ActiveRecord tem um load time de 0.4ms enquanto o Sequel tem um load time de 0.08ms, um ganho de 5x de velocidade!

A gem do sequel tem sido permanentemente estável e muito bem suportada desde sua criação até hoje, o Jeremy Evans seu criador, que mantém as issues perto de ZERO e lança releases geralmente mensais.

SEQUEL vs ActiveRecord

Sintaxe

A sintaxe de ambos é bem similar, o que é uma vantagem por não adicionar grande complexidade na implementação =)

Estamos acostumados a consultar o banco e aguardar que todos os registros da busca sejam carregados para depois serem retornados para uso, isso é o preload.

Preload x Layz fetch

O sequel faz lazy fetch nas suas consultas ao banco de dados.

Aí você pensa: Hmm, legal… que isso?

Com o lazy fetch ele te retorna o resultado a cada busca, não é necessário aguardar todos os registros serem carregados na memória para obter os retornos.

Isso te gera uma economia de load time e memória.

Dataset

Como quase todas as consultas no Sequel são representadas por datasets, e a maioria dos métodos de dataset retornam cópias modificadas de si mesmos. O seu retorno é formato de hash, que é bem fácil de manipular.

Com ele é possível retornar informações de mais de uma tabela no mesmo conjunto de dados, fazer recursão e retornar seus dados na mesma busca, entre outros, pois você pode sobrescrever o dataset conforme sua necessidade.

module DB::Version
 def dataset
 time = 1.week.ago
 original\_data = super
 table\_name = original\_data.first\_source\_alias

original\_data.from(Sequel.lit(\<\<-SQL, time, time))
 (
 SELECT \* FROM #{table\_name}
 WHERE sys\_period @\> ?::timestamptz
 UNION ALL
 SELECT \* from #{table\_name}\_history
 WHERE sys\_period @\> ?::timestamptz
 ) #{table\_name}
 SQL
 end
end

No exemplo acima, temos um exemplo do que citei acima.

Nele, sobrescrevemos o método dataset original da classe para retornar em um mesmo momento os dados atuais e os dados da tabela que guarda as alterações em um registro =)

Sequel & SQL

Desenvolvedorxs adoram escrever código sem ter que recorrer a consultas SQL personalizadas e esse também é um dos plus do Sequel!

Com ele é fácil fazer alias, type cast, operações com string, operações matemáticas, manipulação da estrutura do banco, views e muito mais.

Time is money, não vamos disperdiçá-lo

Num local database, há quase zero latência entre a database and a aplicação;

Quando sua aplicação está usando por exemplo a AWS, com a database e a aplicação em diferentes servidores e na mesma zona, há quase meio milissegundos de latência;

Já quando sua database está em zonas diferentes ainda que no mesmo datacenter, a latência ja sobre para 2 milliseconds e por aí vai….

Isso significa que trabalhar com grandes ou massas de dados leva um tempo muito maior entre a solicitação e a resposta que obtemos.

Na Smart FIT, tinhamos um relatorio que levava 12h para ser rodado apenas para o Brasil. Após implementarmos o Sequel, o tempo de carregamento para TODOS os sete paises caiu para 8h e uns minutos!

Isso aconteceu porque com a implementação do Sequel metodo EAGER ( que faz eaguer load), além de eliminarmos os N+1, eliminamos os callbacks que o AR chama para antes de salvar um registro por padrão.

Além disso, o Sequel implementa o octopus, que faz gerenciamento de pool de conexão multibanco por padrão, enquanto com o ActiveRecord tínhamos que add a “gem octopus” que usa o method missing que torna a resposta 2x mais lenta!

Essas são algumas das vantagens que o Sequel disponibiliza, tanto que desde 2015 o ActiveRecord passou a implementar algumas delas. Sua implentação é muito simples:

gem install 'sequel-rails' ou adicioná-lo ao Gemfile

_Configuração inicial no_ **_application.rb_** _:_

config.sequel.after\_connect = proc do 
 Sequel::Model.plugin :timestamps, update\_on\_create: true 
 Sequel::Model.plugin :update\_or\_create 
 Sequel::Model.plugin :validation\_helpers 
 Sequel::Model.plugin :tactical\_eager\_loading 
end

Criação do seu model:

class DB::State \< Sequel::Model 
 one\_to\_many :cities 
end

class DB::City \< Sequel::Model 
 one\_to\_one :state 
end

e no IRB:
\> DB::State.where(uf: %w(sp rj))

Sequel::Mysql2::Database SELECT \* FROM `states` WHERE (`uf` IN ('sp'))
#\<DB::State [@values](http://twitter.com/values)={:id=\>1, :name=\>"São Paulo", :created\_at=\>2009-06-22 21:13:44 -0300, :updated\_at=\>2016-04-07 18:31:17 -0300, :uf=\>"SP"}\>

\> DB::State.where(uf: %w(sp)).eager(:cities).each do |state|
 p state
 p state.cities
end
 Sequel::Mysql2::Database SELECT \* FROM `states` WHERE (`uf` IN ('sp')) #\<DB::State [@values](http://twitter.com/values)={:id=\>1, :name=\>"São Paulo", :created\_at=\>2009-06-22 21:13:44 -0300, :updated\_at=\>2016-04-07 18:31:17 -0300, :uf=\>"SP"}
Sequel::Mysql2::Database SELECT \* FROM `cities` WHERE (`cities`.`state_id` = 1) [#\<DB::City [@values](http://twitter.com/values)={:id=\>79, :state\_id=\>11, :name=\>"Rio Claro", :created\_at=\>2009-06-22 21:13:54 -0300, :updated\_at=\>2016-06-09 08:06:44 -0300}...

Bem similar ao que conhecemos, não?

Há muito mais em sua documentação, espero ter despertado sua curiosidade para fazer alguns testes e brincadeiras por conta própria!

That’s all folks!

Top comments (0)