Identificar e eliminar o temido produto cartesiano

p> Produtos cartesianos normalmente não fornecem informações úteis e muitas vezes resultam em erros que podem prejudicar a sua carreira de criador de bases de dados. Aprenda a detectar as adesões cartesianas e a bani-las para sempre das suas consultas SELECT.

Nunca esquecerei uma das minhas primeiras tarefas SQL como jovem desenvolvedor júnior no Governo Federal. Tive de produzir um relatório para um dos nossos clientes para o ajudar a gerar algumas estatísticas para o gabinete do ministro. Quando os números do relatório variaram de acordo com as suas próprias estimativas por uma larga margem, convocaram uma reunião entre o meu chefe e eu. Não fazia ideia de onde ou que tinha errado, até o meu patrão ter dito “Robert, você criou um produto cartesiano”. Depois de ela ter terminado de me interrogar em frente dos nossos clientes, a reunião foi adiada e eu saí para reescrever a minha pergunta. Acabei por descobrir o que eles procuravam, mas o meu patrão nunca me deixou vivê-la, e depois disso, em todas as reuniões: “Robert, lembra-te da vez em que criaste um Produto Cartesiano…”. Acabei por me transferir para um departamento diferente cerca de seis meses mais tarde. Agora, é verdade que o meu patrão não era uma pessoa especialmente clemente, mas erros como esses podem realmente prejudicar a sua carreira. Hoje, gostaria de partilhar consigo o que aprendi sobre Produtos Cartesianos ao longo dos anos, para que os possa identificar e banir das suas consultas SELECT para sempre.

Como Gerar um Produto Cartesiano

A consulta seguinte extrai dados de duas tabelas sem qualquer tipo de filtragem. Omitir a cláusula WHERE pode ser útil em situações em que deseja ver todas as linhas de uma tabela mas deseja reordenar ou ocultar colunas não relevantes:

SELECT name, gender, CONCAT('$', FORMAT(salary, 2)) AS 'Monthly Salary' FROM employees, shops; 

O problema aqui é que a consulta selecciona a partir de múltiplas tabelas. Sem qualquer adesão explícita a tabelas, acabamos com uma espécie de adesão por defeito chamada Join Cartesiana (ou Cross Join). O nome Cross Join refere-se ao facto de se juntar cada fila da primeira tabela a cada fila da segunda tabela. Por outras palavras, as Entradas Cartesianas representam a soma do número de colunas das tabelas de entrada mais o produto do número de linhas das tabelas de entrada.

É possível ver nos resultados que cada linha da primeira (empregados) tabela é devolvida para cada linha da segunda (lojas) tabela. Uma vez que existem três linhas na tabela de lojas, a consulta produz três de cada linha da tabela de empregados:

É um lote de linhas para duas pequenas tabelas. Os resultados crescem exponencialmente quando estão envolvidas mais filas e/ou mesas. Devido ao esforço que tal consulta coloca nos recursos do sistema e que o conjunto de dados resultante contém demasiada informação para o autor da consulta seleccionar o que é interessante, as Juntas Cartesianas são quase sempre realizadas por acidente. Como aprendemos no meu próprio conto de advertência, é bom saber como detectar uma antes que os seus clientes ou supervisor lhe voltem com perguntas sobre o porquê de haver tantas filas duplicadas. De facto, a presença de muitos duplicados, combinada com um conjunto de resultados invulgarmente grande, é um sinal indicador de que poderá ter um Produto Cartesiano nas suas mãos.

Como os critérios de filtragem podem mascarar um Produto Cartesiano

DeclaraçõesSELECT que contêm uma cláusula WHERE podem facilmente esconder um Produto Cartesiano porque nem todas as filas aparecerão em duplicado. Aqui está uma consulta de aspecto inocente o suficiente na qual alguém se esqueceu de incluir uma junta de tabela:

SELECT name, gender, CONCAT('$', FORMAT(salary, 2)) AS 'Monthly Salary' FROM shops, employeesWHERE shops.shop = 'Zurich';

Desde que a loja não apareça no conjunto de resultados, seria fácil aceitar a saída para ser precisa. Contudo, podemos facilmente verificar que apenas os dois primeiros empregados da lista trabalham em Zurique. Os outros três parecem ter escapado aos nossos critérios de filtragem!

O resultado de todas as colunas mostra mais claramente o que se está a passar. De facto, o filtro apenas devolveu a loja em Zurique. No entanto, sem uma tabela adequada juntar-se à consulta produz um registo para cada empregado, quer estejam ou não ligados à loja de Zurique. Isto faz sentido quando se considera que os empregados não estão associados a nenhuma loja sem uma adesão. Assim, o campo shop_id na tabela de empregados não tem nada a ver com o das lojas. O que a pergunta diz é “Traga-me todas as filas da tabela das lojas onde o nome corresponde a ‘Zurique’ e todas as filas da tabela dos empregados”:

shop_id

shop

id

shop_id_1

gender

p>nome

salary

Zurique

m

Jon Simpson

Zurique

f

>/td>

Barbara Breitenmoser

(NULL)

Zurique

f

Kirsten Ruegg

Zurique

m

Ralph Teller

Zurique

m

p>Peter Jonson

Similiarmente, estreitando os resultados da tabela de empregados produz apenas linhas dessa tabela que correspondem aos critérios e todas as linhas da outra tabela. Aqui está uma consulta que filtra os empregados por salário:

SELECT name, gender, CONCAT('$', FORMAT(salary, 2)) AS 'Monthly Salary' FROM shops, employeesWHERE employees.salary > 5500;

Corresponde a uma linha da tabela de empregados, que é apresentada uma vez para cada linha da tabela de lojas:

nome

género

Salário Mensal

Kirsten Ruegg

f

$5,600.00

Kirsten Ruegg

f

$5.600.00

Kirsten Ruegg

f

$5.600.00

Again, incluindo todas as colunas confirma esta suposição:

id

>/td>

p>shop_id

gender

nome

/td>

salary

loja_id_1

shop

/td>

f

Kirsten Ruegg

Zurique

f

Kirsten Ruegg

Nova Iorque

f

Kirsten Ruegg

London

Agora estes resultados não parecem imediatamente suspeitos porque, dependendo dos critérios e das colunas que são exibidas, os valores duplicados não são uma ocorrência invulgar:

A consulta continua a exibir um empregado para cada linha da tabela de lojas, mas desta vez exibe um empregado para cada linha da tabela de lojas, bem como três linhas para o empregado correspondente. Por outras palavras, todos os cinco empregados são exibidos para as lojas correspondentes (a de Zurique) e o registo do empregado cujo rendimento exceda $5500 (Kristen Ruegg) é repetido para cada linha da tabela de lojas.

Como vimos hoje, os Produtos Cartesianos não tendem a fornecer informações úteis. Portanto, a moral da história é a seguinte: evite as Juntas Cartesianas a todo o custo, a menos que tenha uma razão cristalina para o fazer.

Obtendo os Dados Corretos com Juntas SQL

” Ver Todos os Artigos do Colunista Rob Gravelle

Deixe uma resposta

O seu endereço de email não será publicado. Campos obrigatórios marcados com *