Sequel para ActiveRecord heavy-users

debborafernandess

Débora Fernandes

Posted on October 8, 2019

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!

💖 💪 🙅 🚩
debborafernandess
Débora Fernandes

Posted on October 8, 2019

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related

Sequel para ActiveRecord heavy-users
sequels Sequel para ActiveRecord heavy-users

October 8, 2019