Movatterモバイル変換


[0]ホーム

URL:


Skip to content
DEV Community
Log in Create account

DEV Community

Guilherme Rodrigues
Guilherme Rodrigues

Posted on • Edited on

     

Aplicação 397x mais rápida com desnormalização

Quando trabalhamos com bancos de dados relacionais, é comum nos depararmos com situações onde precisamos contar registros relacionados em uma tabela.

Primeiramente vamos considerar as seguintes tabelas:

CREATETABLEorders(order_idSERIALPRIMARYKEY,order_dateDATE,customerVARCHAR(100));CREATETABLEorder_items(item_idSERIALPRIMARYKEY,order_idINT,productVARCHAR(100),quantityINT,FOREIGNKEY(order_id)REFERENCESorders(order_id));
Enter fullscreen modeExit fullscreen mode

Temos uma tabela deorders e queremos contar quantos itens cada pedido possui. Uma abordagem comum seria usar uma subquery com COUNT:

SELECTo.order_id,(SELECTCOUNT(*)FROMorder_itemsoiWHEREoi.order_id=o.order_id)AStotal_itemsFROMorderso;
Enter fullscreen modeExit fullscreen mode

Essa query funciona, mas pode se tornar ineficiente em cenários com grandes volumes de dados, pois a subquery é executada para cada linha da tabelaorders.

Aqui entra adesnormalização!

A desnormalização em bancos de dados é o processo de introduzir redundância em um banco de dados previamente normalizado, com o objetivo de melhorar o desempenho em operações de leitura (consultas). Envolve a adição de dados duplicados ou a combinação de tabelas para reduzir o número de operações necessárias (joins, counts...), o que pode acelerar a recuperação de informações em sistemas onde a leitura é mais frequente que a escrita.

Agora sabemos o que é desnormalização como podemos simplificar nossa query?
Em vez de contar os itens toda vez que executamos a query, podemos adicionar um campototal_items diretamente na tabelaorders. E sempre que um item for adicionado ou removido, incrementamos ou decrementamos esse campo.

Como fazer isso?

  1. Adicione o campototal_items na tabelaorders:
ALTERTABLEordersADDCOLUMNtotal_itemsINTDEFAULT0;
Enter fullscreen modeExit fullscreen mode
  1. Atualize o campototal_items sempre que um item for adicionado ou removido

  2. Sua query fica muito mais simples e eficiente:

SELECTorder_id,total_itemsFROMorders;
Enter fullscreen modeExit fullscreen mode

Vamos inserir dados para podermos validar nossa proposta, podemos inserir uma massa de dados com a seguinte função:

CREATEORREPLACEFUNCTIONgenerate_sample_data()RETURNSVOIDAS$$DECLAREorder_countINT:=200;items_per_orderINT:=10;current_order_idINT;random_customerVARCHAR(100);random_productVARCHAR(100);random_quantityINT;BEGINFORiIN1..order_countLOOPrandom_customer:='Customer '||(floor(random()*1000)::INT);INSERTINTOorders(order_date,customer,total_items)VALUES(current_date-(floor(random()*365)::INT),random_customer,10)RETURNINGorder_idINTOcurrent_order_id;FORjIN1..items_per_orderLOOPrandom_product:='Product '||(floor(random()*100)::INT);random_quantity:=(floor(random()*10)::INT+1;INSERTINTOorder_items(order_id,product,quantity)VALUES(current_order_id,random_product,random_quantity);ENDLOOP;ENDLOOP;END;$$LANGUAGEplpgsql;SELECTgenerate_sample_data();
Enter fullscreen modeExit fullscreen mode

No script anterior basicamente criamos 200 registros na tabelaorders e 10 registros na tabelaorder_items para cadaorder.

Para compararmos e validarmos nossa hipótese vamos executar nossas queries comexplain analyse e teremos o seguinte resultado:

Utilizando a subquery:

Query com count

Podemos ver que executando a consulta com a subquery o execution time é igual a28.983ms

Utilizando o campo criado na desnormalização:

query aplicando desnormalização

Sem a subquery nosso resultado é0.073ms. Sendo assim397 vezes mais rápido e vale ressaltar quecriamos apenas 200 registros na tabelaorders, quantomais registros criarmos mais a query com subquery serálenta e a query desnormalizada irá se manter na mesma média.

Vantagens:

Performance: Evita a execução de subqueries repetidas.
Simplicidade: A query principal fica mais limpa e fácil de entender.
Controle: Você tem um controle direto sobre o valor do contador.

Cuidados:

Consistência: É preciso garantir que o campo total_items seja sempre atualizado corretamente.
Concorrência: Em sistemas com alta concorrência, é importante garantir que as atualizações sejam atômicas para evitar inconsistências.

Espero que esse conteúdo tenha sido útil para você!

Top comments(0)

Subscribe
pic
Create template

Templates let you quickly answer FAQs or store snippets for re-use.

Dismiss

Are you sure you want to hide this comment? It will become hidden in your post, but will still be visible via the comment'spermalink.

For further actions, you may consider blocking this person and/orreporting abuse

A backend software engineer, Go and performance enthusiast
  • Joined

More fromGuilherme Rodrigues

DEV Community

We're a place where coders share, stay up-to-date and grow their careers.

Log in Create account

[8]ページ先頭

©2009-2025 Movatter.jp