Benchmark: ORM vs SQL puro

Finalmente tive tempo para sanar, com dados, uma das minhas e, imagino que de várias outras pessoas, maiores dúvidas quando se trata de Go e banco de dados. Qual a diferença, ao nível de consumo de recurso e performance, entre utilizar GORM vs escrever SQL na unha.

Para ficar mais fácil a leitura, separei o post em tópicos. Iniciarei explicando como fiz o setup, as funções comuns e realizei a execução dos benchmarks. Depois, separo o código do benchmark, assim como o resultado, em ações de CRUD.

Setup

Primeiramente, criei os packages entities, orm e std. Dentro do package entities, criei uma struct para ser utilizada em todos os benchmarks.

package entities

type Category struct {
    ID          int64  `gorm:"column:id;primaryKey"`
    Name        string `gorm:"column:name"`
    Description string `gorm:"column:description"`
}
Leia mais »

Benchmark: conexão sempre aberta vs uma conexão por chamada

Como eu nunca havia visto um benchmark para mostrar as diferenças entre, abrir uma conexão no início do programa e utilizá-la como dependência e, abrir uma nova conexão a cada chamada, resolvi fazê-la.

Embora a maioria das pessoas que converso saberem a resposta correta, não sei se, assim como eu, elas têm a ideia de quão grande é a diferença entre essas abordagens.

Mas antes de ver o resultado, mostrarei como construí o benchmark.

Conexão & Dados

Bem simples, para abrir a conexão sqlite3, criei uma função chamada Open.

package connections  

import (  
    "database/sql"  

    _ "github.com/mattn/go-sqlite3"  
)  

// Open a connection with a sqlite3 database
func Open() (*sql.DB, error) {  
    return sql.Open("sqlite3", "test.db")  
}
Leia mais »
snow top mountain under clear sky

Como implementar uma função utilizando context

Nesse post vamos implementar uma função que utiliza context. No exemplo de chamada, vou utilizar o context WithTimeout. Dessa forma, conseguiremos fazer a função ser cancelada automaticamente, caso o tempo de execução dela ultrapasse o tempo estipulado no context.

Vamos iniciar criando uma função com o nome doSomeHeavyWork.

func doSomeHeavyWork(ctx context.Context, msg string) {
}

Para simular um processamento longo, vamos adicionar uma goroutine com um sleep de 2 segundos. Essa goroutine irá receber um channel do tipo bool. Ele irá sinalizar que a goroutine foi finalizada.

Leia mais »
crop nurse with syringe ready to vaccinate patients

O que é e como utilizar Dependency Injection

Se você já ouviu falar mas não sabe ao certo o que é Dependency Injection ou como a utilizar em Golang, nesse post espero te ajudar a sanar as duas dúvidas.

Para que todos estejam na mesma página, antes de ver como utilizar, vamos falar um pouco sobre o que é essa tal Dependency Injection ou DI para os íntimos.

Podemos definir DI (Dependency Injection) como uma técnica onde os módulos recebem todas ou parte de suas dependências de forma indireta, ou seja, por parâmetro em uma função/método ou sendo passada diretamente para o campo de uma struct, onde tais parâmetros ou campos não tenham um tipo definido, mas sim uma interface.

Vantagens da Dependency Injection

Utilizar essa técnica ajuda com que nosso código tenha baixo acoplamento, o que torna a tarefa de refatorar partes do sistema muito mais fácil.

Leia mais »
high angle view of people on bicycle

Como resolver race condition com sync/atomic

Algum tempo atrás, publicamos um post aqui no blog explicando como resolver race condition utilizando mutex e channels.

Embora o conteúdo daquele post continue sendo válido, para alguns casos mais simples de race condition, como por exemplo o do post, podemos utilizar o package sync/atomic para nos auxiliar.

Para dar o ponta pé inicial, vamos escrever um código que não irá funcionar corretamente por haver race condition.

package main

import (
	"fmt"
	"sync"
)

func main() {
	var total int64

	var wg sync.WaitGroup

	for i := 0; i < 50; i++ {
		wg.Add(1)

		go func() {
			for c := 0; c < 1000; c++ {
				total += int64(c)
			}
			wg.Done()
		}()
	}

	wg.Wait()

	fmt.Println(total)
}
Leia mais »
depth of field photography of file arrangement

Como listar arquivos de um diretório

Nesse post vou mostrar três formas diferentes para ler um diretório com Golang.

[SPOILER ALERT] No final desse post vou mostrar como eu apliquei um dos exemplos para poder ler um diretório que continha mais de 3.6 milhões de arquivos.

Vamos iniciar os exemplos utilizando a função ReadDir do package ioutil.

package main

import (
    "fmt"
    "io/ioutil"
    "log"
)

func main() {
    files, err := ioutil.ReadDir("/tmp/")
    if err != nil {
        log.Fatal(err)
    }

    for _, file := range files {
        fmt.Println(file.Name(), file.IsDir())
    }
}
Leia mais »

Como conectar e fazer CRUD em um banco PostgreSQL

Quando desenvolvemos programas que vão trabalhar com dados, sem sombra de dúvida uma das coisas mais importantes é armazenar esses dados com segurança e robustez.

Nesse post, vou mostrar como conectar e executar um CRUD utilizando um banco de dados PostgreSQL.

Antes de começar a escrever código, vamos fazer download do drive do postgres para Go com o comando go get github.com/lib/pq.

Ok, agora podemos começar.

Para ficar um pouco mais próximo da realidade, vou separar todas as operações em funções, incluindo a conexão com o banco.

Leia mais »

Trabalhando com datas

Acho que um dos assuntos que mais causa confusão, depois talvez de goroutines e channels, é a manipulação de datas em Go.

Nesse post vou mostrar como manipular, comparar, formatar e fazer parse de datas em Go.

Para iniciar, vamos “printar” a data atual da forma mais simples possível.

package main

import (
    "fmt"
    "time"
)

func main() {
    now := time.Now()
    fmt.Println(now)
}
Leia mais »

Como utilizar generics em structs

A partir da versão 1.18 do Go, FINALMENTE temos o generics disponível para utilização. Em outros posts, que vou deixar aqui em baixo, já abordamos como utilizar generics em funções, como utilizar a contraint comparable e fizemos um pequeno benchmark para ver a diferença com funções comuns.

Essa semana enquanto fuçava no código fonte do Go, descobri que também podemos utilizar essa maravilha em structs.

Para demonstrar como utiliza-lo, vamos criar uma struct para fazer cache das structs PessoaFisica e PessoaJuridica.

Leia mais »

Cavando o Fonte #02 – O package Path

Nesse segundo vídeo da série “Cavando o Fonte”, vamos explorar o package path e ver como algumas das suas funções mais utilizadas são implementadas.

Deixem suas dúvidas nos comentários.

Até a próxima!


Se inscreva na nossa newsletter

* indicates required