Is query
set with Where
or other sql commands inside loops like Foreach
good practice or not recommended at all? Is there a better way to handle the data without having to make so many calls in the database?
Is query
set with Where
or other sql commands inside loops like Foreach
good practice or not recommended at all? Is there a better way to handle the data without having to make so many calls in the database?
TL; DR : No, it's not good practice.
Long answer:
As a general rule, assume that it is always best to insert as little overhead as possible into whatever process you are mapping.
In case of several queries being executed within a loop you are saturating the database with requests.
The implementation differences between the DBMSs are saved, each has a cost: query is interpreted, mapped, has its execution plan evaluated, its competition with other queries evaluated, reserved memory pages and searched indexes, among other processes.
That said, let's get some possibilities. I'll list the method you described first.
In this simulation,
TABELA1
has 10 records TABELA2
has 100 records TABELA2
. T1ID
to TABELA1
. ID
TABELA2
for each record in TABELA1
Case 1: Serial calls
-- Primeira pesquisa no banco de dados. Retorna 10 registros.
> SELECT ID, NOME FROM TABELA1 T1
-- Loop. Uma chamada para cada linha no retorno da consulta acima:
> SELECT ID, NOME FROM TABELA2 T2 WHERE T2.T1ID = 1
> SELECT ID, NOME FROM TABELA2 T2 WHERE T2.T1ID = 2
> SELECT ID, NOME FROM TABELA2 T2 WHERE T2.T1ID = 3
> SELECT ID, NOME FROM TABELA2 T2 WHERE T2.T1ID = 4
> SELECT ID, NOME FROM TABELA2 T2 WHERE T2.T1ID = 5
> SELECT ID, NOME FROM TABELA2 T2 WHERE T2.T1ID = 6
> SELECT ID, NOME FROM TABELA2 T2 WHERE T2.T1ID = 7
> SELECT ID, NOME FROM TABELA2 T2 WHERE T2.T1ID = 8
> SELECT ID, NOME FROM TABELA2 T2 WHERE T2.T1ID = 9
> SELECT ID, NOME FROM TABELA2 T2 WHERE T2.T1ID = 10
-- 11 chamadas são realizadas ao banco de dados.
Case 2: Concatenation via UNION
-- Você pode concatenar suas chamadas dentro do loop,
-- e solicitar uma única chamada.
-- Primeira pesquisa no banco de dados. Retorna 10 registros.
> SELECT ID, NOME FROM TABELA1 T1
-- Loop e concatenação. Uma chamada contendo o seguinte texto:
> SELECT ID, NOME FROM TABELA2 T2 WHERE T2.T1ID = 1 UNION
SELECT ID, NOME FROM TABELA2 T2 WHERE T2.T1ID = 2 UNION
SELECT ID, NOME FROM TABELA2 T2 WHERE T2.T1ID = 3 UNION
SELECT ID, NOME FROM TABELA2 T2 WHERE T2.T1ID = 4 UNION
SELECT ID, NOME FROM TABELA2 T2 WHERE T2.T1ID = 5 UNION
SELECT ID, NOME FROM TABELA2 T2 WHERE T2.T1ID = 6 UNION
SELECT ID, NOME FROM TABELA2 T2 WHERE T2.T1ID = 7 UNION
SELECT ID, NOME FROM TABELA2 T2 WHERE T2.T1ID = 8 UNION
SELECT ID, NOME FROM TABELA2 T2 WHERE T2.T1ID = 9 UNION
SELECT ID, NOME FROM TABELA2 T2 WHERE T2.T1ID = 10
-- 2 chamadas são realizadas ao banco de dados.
Case 3: IN Clause
-- Vários SGBDs implementam a cláusula IN:
-- Primeira pesquisa no banco de dados. Retorna 10 registros.
> SELECT ID, NOME FROM TABELA1 T1
-- Loop e concatenação em um único parâmetro:
> SELECT ID, NOME FROM TABELA2 T2 WHERE T2.T1ID IN (1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
-- 2 chamadas. Muito menos conteúdo a ser interpretado
-- pelo SGDB do que o caso 3.
Case 4a: SubQuery
> SELECT ID, NOME
FROM TABELA2 T2
WHERE T2.T1ID IN
(
SELECT ID
FROM TABELA1 T1
)
-- Uma única chamada ao banco.
Case 4b: JOIN
> SELECT ID, NOME
FROM TABELA2 T2
JOIN TABELA1 T1
ON T2.T1ID = T1.ID
-- Uma única chamada ao banco. Em alguns SGDBs, mais performático do que 4a.