Sequel para ActiveRecord heavy-users
Tags: sequels, rails, performance
Published: 2019-10-08 23:44:49

---
title: Sequel para ActiveRecord heavy-users
published: true
date: 2018-07-23 18:05:42 UTC
tags: sequels,ruby-on-rails,rails,performance
canonical_url: https://medium.com/@debborafernandess/sequel-para-activerecord-heavy-users-5baedabb7946
---

“_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](http://sequel.jeremyevans.net/rdoc/classes/Sequel/Dataset.html)

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](http://sequel.jeremyevans.net/rdoc/files/doc/sql_rdoc.html)

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](http://sequel.jeremyevans.net/rdoc/files/doc/sql_rdoc.html#label-Aliasing), [type cast](http://sequel.jeremyevans.net/rdoc/files/doc/sql_rdoc.html#label-Casts), 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](http://sequel.jeremyevans.net/documentation.html), espero ter despertado sua curiosidade para fazer alguns testes e brincadeiras por conta própria!

That’s all folks!

​

​