Do not speak Portuguese? Translate this site with Google or Bing Translator
Laravel usando agregação condicional

Posted on: June 29, 2022 12:21 AM

Posted by: Renato

Views: 1013

# Otimizando o cálculo de totais no Laravel usando agregação condicional

## Create Table PostgreSQL


```sql
CREATE TABLE IF NOT EXISTS public.orders
(
    id serial PRIMARY KEY,    
    customer character varying(255) NOT NULL,
    status character varying(100) NOT NULL,
    price numeric(15,2),
    created_at timestamp(0) without time zone,
    updated_at timestamp(0) without time zone    
);
```

## Insert


```sql
INSERT INTO "public"."orders" ("customer", "status", "price", "created_at", "updated_at") VALUES ('Edna Cardoso', 'canceled', '3602497', '2022-06-28 17:53:20', '2022-06-28 17:53:23');
INSERT INTO "public"."orders" ("customer", "status", "price", "created_at", "updated_at") VALUES ('Renato Lucena', 'approved', '480832', '2022-06-28 17:53:20', '2022-06-28 17:53:23');
INSERT INTO "public"."orders" ("customer", "status", "price", "created_at", "updated_at") VALUES ('Alexandre Philype', 'finished', '1000', '2022-06-28 17:53:20', '2022-06-28 17:53:23');
INSERT INTO "public"."orders" ("customer", "status", "price", "created_at", "updated_at") VALUES ('Jonathan Costa', 'shipped', '20987316', '2022-06-28 17:53:20', '2022-06-28 17:53:23');
INSERT INTO "public"."orders" ("customer", "status", "price", "created_at", "updated_at") VALUES ('Mrs.Leidiany Lucena', 'approved', '1000', '2022-06-28 17:53:20', '2022-06-28 17:53:23');
INSERT INTO "public"."orders" ("customer", "status", "price", "created_at", "updated_at") VALUES ('Thiago Costa', 'finished', '1000', '2022-06-28 17:53:20', '2022-06-28 17:53:23');
INSERT INTO "public"."orders" ("customer", "status", "price", "created_at", "updated_at") VALUES ('Marcos Costa', 'approved', '4747', '2022-06-28 17:53:20', '2022-06-28 17:53:23');
INSERT INTO "public"."orders" ("customer", "status", "price", "created_at", "updated_at") VALUES ('Francisco Jose de Lucena', 'shipped', '767992', '2022-06-28 17:53:20', '2022-06-28 17:53:23');
INSERT INTO "public"."orders" ("customer", "status", "price", "created_at", "updated_at") VALUES ('Josefa de O. Lucena', 'finished', '102895', '2022-06-28 17:53:20', '2022-06-28 17:53:23');
```

Nesse artigo vou falar sobre algo que todo dev já deve ter trabalhado na vida: otimização/melhoria de consultas SQL no backend. Mais especificamente, a otimização de consultas de cálculos de totais.

O banco de dados executa todas as consultas de forma coletiva e existem limites (conexões, CPU, memória), que definem o número de consultas que pode ser executado de uma vez. Assim, todos endpoints da sua aplicação são importantes na perspectiva do desempenho do banco de dados.

Devemos tratar o BD como um recurso compartilhado por todos os usuários da sua aplicação, onde cada consulta executada pelo banco de dados utiliza um pouco desse recurso finito. Rode muitas consultas pesadas ao mesmo tempo e ele pode chegar no limite.

Então, precisamos encontrar as consultas que demandam mais recursos e otimizá-las. Normalmente essas consultas são aquelas que calculam algum tipo de total e principalmente quando múltiplos totais são necessários na mesma requisição. Vamos ao exemplo:

Digamos que temos uma tabela no banco de dados chamada orders com dados neste formato:

id|customer                |status  |price      |created_at         |updated_at         |
--|------------------------|--------|-----------|-------------------|-------------------|
 1|Renato Lucena           |approved|  480832.00|2022-06-28 17:53:20|2022-06-28 17:53:23|
 3|Edna Cardoso            |canceled| 3602497.00|2022-06-28 17:53:20|2022-06-28 17:53:23|
 4|Alexandre Philype       |finished|    1000.00|2022-06-28 17:53:20|2022-06-28 17:53:23|
 5|Jonathan Costa          |shipped |20987316.00|2022-06-28 17:53:20|2022-06-28 17:53:23|
 6|Mrs.Leidiany Lucena     |approved|    1000.00|2022-06-28 17:53:20|2022-06-28 17:53:23|
 7|Thiago Costa            |finished|    1000.00|2022-06-28 17:53:20|2022-06-28 17:53:23|
 8|Marcos Costa            |approved|    4747.00|2022-06-28 17:53:20|2022-06-28 17:53:23|
 9|Francisco Jose de Lucena|shipped |  767992.00|2022-06-28 17:53:20|2022-06-28 17:53:23|
10|Josefa de O. Lucena     |finished|  102895.00|2022-06-28 17:53:20|2022-06-28 17:53:23|

Desejamos mostrar os seguintes totais de pedidos para o usuário:

    Aprovados: X
    Finalizados: X
    Cancelados: X
    Enviados: X
    Total: X

Uma das maneiras mais fáceis para realizar o cálculo desses totais é a seguinte:

```
 public function index()
  {
    $total = Order::count();
    $approved = Order::where('status', 'approved')->count();
    $finished = Order::where('status', 'finished')->count();
    $canceled = Order::where('status', 'canceled')->count();
    $shipped = Order::where('status', 'shipped')->count();
    dd($canceled);
  }
```

O problema dessa maneira é a execução de cinco consultas no banco de dados, o que sabemos que não é muito bom. Pra resolver, podemos tentar otimizar o código utilizando as Collections do Eloquent, ficaria assim:

```
  public function collection()
  {
    $orders = Order::all();
    $total = $orders->count();
    $approved = $orders->where('status', 'approved')->count();
    $finished = $orders->where('status', 'finished')->count();
    $canceled = $orders->where('status', 'canceled')->count();
    $shipped = $orders->where('status', 'shipped')->count();
    dd($approved);
  }
 
```

Com essa otimização temos apenas uma consulta no banco de dados. Problema resolvido, então? Nope! Esse método é pior do que o anterior. Isso ocorre pois, apesar de termos somente uma consulta ao banco de dados, a contagem dos resultados está sendo executada pelo Collection do Eloquent, ou seja, pelo PHP.

## Agregação condicional

Nesse caso, a agregação condicional pode ser utilizada para calcular todos os totais com somente uma consulta, como no exemplo:

```
select
    count(*) as total,
    count(case when status = 'approved' then 1 end) as approved,
    count(case when status = 'finished' then 1 end) as finished,
    count(case when status = 'canceled' then 1 end) as canceled,
    count(case when status = 'shipped' then 1 end) as shipped
from orders;
```


Resultado da execução da consulta:

total|approved|finished|canceled|shipped|
-----|--------|--------|--------|-------|
    9|       3|       3|       1|      2|
    

### Convertendo essa consulta SQL para o Eloquent temos:

 

```
public function eloquent()
  {
    $totals = DB::table('orders')
      ->selectRaw('count(*) as total')
      ->selectRaw("count(case when status = 'approved' then 1 end) as approved")
      ->selectRaw("count(case when status = 'finished' then 1 end) as finished")
      ->selectRaw("count(case when status = 'canceled' then 1 end) as canceled")
      ->selectRaw("count(case when status = 'shipped' then 1 end) as shipped")
      ->first();
    dd($totals);
  }
```

## Muito massa né?

Tente usar as agregações condicionais na próxima vez que criar um painel ou algum outro tipo de resumo de dados em sua aplicação. Seu banco de dados vai ficar feliz!

Abaixo temos a comparação do desempenho das 3 maneiras apresentadas para cálculo de totais, utilizando um banco de dados com 500mil registros:

    - 5 consultas separadas: 0.14 ms;
    - 1 consulta e count no Eloquent Collections: 20.14 ms;
    - 1 consulta usando agregação condicional: 0.09 ms;

Lembre-se de que qualquer consulta que você possa fazer com mais rapidez ou evitar totalmente ajudará o desempenho de todo o sistema. Toda consulta é importante!
 





## Fonte:
- https://medium.com/devorando/otimizando-o-c%C3%A1lculo-de-totais-no-laravel-lumen-usando-agrega%C3%A7%C3%A3o-condicional-ed6f74f49c53

 
 

 

 


4

Share

Donate to Site


About Author

Renato

Developer

Add a Comment
Comments 0 Comments

No comments yet! Be the first to comment

Blog Search


Categories

OUTROS (16) Variados (109) PHP (133) Laravel (171) Black Hat (3) front-end (29) linux (114) postgresql (39) Docker (28) rest (5) soap (1) webservice (6) October (1) CMS (2) node (7) backend (13) ubuntu (56) devops (25) nodejs (5) npm (3) nvm (1) git (8) firefox (1) react (7) reactnative (5) collections (1) javascript (7) reactjs (8) yarn (0) adb (1) Solid (2) blade (3) models (1) controllers (0) log (1) html (2) hardware (3) aws (14) Transcribe (2) transcription (1) google (4) ibm (1) nuance (1) PHP Swoole (5) mysql (31) macox (4) flutter (1) symfony (1) cor (1) colors (2) homeOffice (2) jobs (3) imagick (2) ec2 (1) sw (1) websocket (2) markdown (1) ckeditor (1) tecnologia (14) faceapp (1) eloquent (14) query (4) sql (40) ddd (3) nginx (9) apache (4) certbot (1) lets-encrypt (3) debian (12) liquid (1) magento (2) ruby (1) LETSENCRYPT (1) Fibonacci (1) wine (1) transaction (1) pendrive (1) boot (1) usb (1) prf (1) policia (2) federal (1) lucena (1) mongodb (4) paypal (1) payment (1) zend (1) vim (4) ciencia (6) js (1) nosql (1) java (1) JasperReports (1) phpjasper (1) covid19 (1) saude (1) athena (1) cinnamon (1) phpunit (2) binaural (1) mysqli (3) database (42) windows (6) vala (1) json (2) oracle (1) mariadb (4) dev (12) webdev (24) s3 (4) storage (1) kitematic (1) gnome (2) web (2) intel (3) piada (1) cron (2) dba (18) lumen (1) ffmpeg (2) android (2) aplicativo (1) fedora (2) shell (4) bash (3) script (3) lider (1) htm (1) csv (1) dropbox (1) db (3) combustivel (2) haru (1) presenter (1) gasolina (1) MeioAmbiente (1) Grunt (1) biologia (1) programming (22) performance (3) brain (1) smartphones (1) telefonia (1) privacidade (1) opensource (3) microg (1) iode (1) ssh (3) zsh (2) terminal (3) dracula (1) spaceship (1) mac (2) idiomas (1) laptop (2) developer (37) api (5) data (1) matematica (1) seguranca (2) 100DaysOfCode (9) hotfix (1) documentation (1) laravelphp (10) RabbitMQ (3) Elasticsearch (1) redis (2) Raspberry (4) Padrao de design (4) JQuery (1) angularjs (4) Dicas (43) Kubernetes (3) vscode (2) backup (1) angular (3) servers (2) pipelines (1) AppSec (1) DevSecOps (4) rust (1) RustLang (1) Mozilla (1) algoritimo (1) sqlite (1) Passport (2) jwt (5) security (2) translate (1) kube (2) iot (1) politica (2) bolsonaro (1) flow (1) podcast (1) Brasil (1) containers (3) traefik (1) networking (1) host (1) POO (2) microservices (2) bug (1) cqrs (1) arquitetura (3) Architecture (4) sail (3) militar (1) artigo (1) economia (1) forcas armadas (1) ffaa (1) autenticacao (2) autorizacao (2) authentication (4) authorization (3) NoCookies (1) wsl (4) memcached (1) macos (2) unix (2) kali-linux (1) linux-tools (5) apple (1) noticias (2) composer (1) rancher (1) k8s (1) escopos (1) orm (1) jenkins (4) github (5) gitlab (3) queue (1) Passwordless (1) sonarqube (1) phpswoole (1) laraveloctane (1) Swoole (1) Swoole (1) octane (1) Structurizr (1) Diagramas (1) c4 (1) c4-models (1) compactar (1) compression (1) messaging (1) restfull (1) eventdrive (1) services (1) http (1) Monolith (1) microservice (1) historia (1) educacao (1) cavalotroia (1) OOD (0) odd (1) chatgpt (1) openai (3) vicuna (1) llama (1) gpt (1) transformers (1) pytorch (1) tensorflow (1) akitando (1) ia (1) nvidia (1) agi (1) guard (1) multiple_authen (2) rpi (1) auth (1) auth (1) livros (2) ElonMusk (2) Oh My Zsh (1) Manjaro (1) BigLinux (2) ArchLinux (1) Migration (1) Error (1) Monitor (1) Filament (1) LaravelFilament (1) replication (1) phpfpm (1) cache (1) vpn (1) l2tp (1) zorin-os (1) optimization (1) scheduling (1) monitoring (2) linkedin (1) community (1) inteligencia-artificial (2) wsl2 (1) maps (1) API_KEY_GOOGLE_MAPS (1) repmgr (1) altadisponibilidade (1) banco (1) modelagemdedados (1) inteligenciadedados (4) governancadedados (1) bancodedados (2) Observability (1) picpay (1) ecommerce (1) Curisidades (1) Samurai (1) KubeCon (1) GitOps (1) Axios (1) Fetch (1) Deepin (1) vue (4) nuxt (1) PKCE (1) Oauth2 (2) webhook (1) TypeScript (1) tailwind (1) gource (2)

New Articles



Get Latest Updates by Email