Banco de dados
Todos os sistemas Rails usam PostgreSQL. As bases do Syens e do Salus são grandes (milhares de migrations), então cuidados com performance e integridade não são opcionais.
Migrations
- Toda mudança de schema entra por migration reversível (
changecom operações reversíveis, ouup/down). - Adicione constraints no banco: chaves estrangeiras,
null: falsee índices únicos, além das validações de modelo. - Crie índices para colunas usadas em
WHERE,ORDER BYouJOIN. - Em tabelas grandes, avalie o impacto da migration antes de rodar em produção (bloqueios e tempo de execução).
class AddIndexesToAttendances < ActiveRecord::Migration
def change
add_index :attendances, [:classroom_id, :date]
add_foreign_key :attendances, :classrooms
change_column_null :attendances, :classroom_id, false
end
end
O schema.rb é a fonte de verdade do schema e é versionado.
Performance (não-negociável)
Estas regras valem para todo código que toca o banco:
- Prefira operações no banco a iterar em Ruby para dados em massa:
update_all,delete_all,pluck. - Não carregue grandes conjuntos na memória — use
find_each/find_in_batches. - Use
counter_cachepara contagens frequentes de associações. - Mova operações pesadas (relatórios, exportações, e-mails em massa) para o Sidekiq.
# Em vez de carregar tudo e iterar
Student.where(school_id: school.id).find_each do |student|
# processa em lotes, sem estourar a memória
end
# Apenas uma coluna? use pluck
ids = Enrollment.where(school_year_id: year.id).pluck(:student_id)
Prevenção de N+1
Sempre use includes, preload ou eager_load quando for acessar associações em
um loop (inclusive dentro de views e serializers).
# Ruim: 1 query para turmas + N queries para a escola de cada uma
classrooms.each { |c| puts c.school.name }
# Bom: pré-carrega a associação
Classroom.includes(:school).each { |c| puts c.school.name }
Regra prática: depois de escrever uma query que renderiza uma coleção, percorra mentalmente a view/serializer e confira se alguma associação é acessada por registro.