A chave estrangeira melhora o desempenho da consulta?

149

Suponha que eu tenha 2 tabelas, produtos e categorias de produtos. Ambas as tabelas têm relação no CategoryId. E esta é a consulta.

SELECT p.ProductId, p.Name, c.CategoryId, c.Name AS Category
FROM Products p
INNER JOIN ProductCategories c ON p.CategoryId = c.CategoryId
WHERE c.CategoryId = 1;

Quando crio o plano de execução, a tabela ProductCategories executa a busca de índice de cluster, que é a expectativa. Mas para a tabela Products, ele executa a verificação de índice de cluster, o que me faz duvidar. Por que o FK não ajuda a melhorar o desempenho da consulta?

Então, eu tenho que criar um índice em Products.CategoryId. Quando crio o plano de execução novamente, as duas tabelas executam a busca de índice. E o custo estimado da subárvore é bastante reduzido.

Minhas perguntas são:

  1. Ao lado de FK ajuda na restrição de relacionamento, ela tem outra utilidade? Melhora o desempenho da consulta?

  2. Devo criar um índice em todas as colunas do FK (como Products.CategoryId) em todas as tabelas?

Chaowlert Chaisrichalermpol
fonte

Respostas:

186

Chaves estrangeiras são uma ferramenta de integridade referencial, não uma ferramenta de desempenho. Pelo menos no SQL Server, a criação de um FK não cria um índice associado e você deve criar índices em todos os campos do FK para melhorar os tempos de pesquisa.

cmsjr
fonte
40
Bons modelos (geralmente) têm melhor desempenho.
Kenny Evitt
10
"Chaves estrangeiras são uma ferramenta de integridade relacional" - use a palavra 'relacional' com cuidado. Chaves estrangeiras são um conceito de banco de dados, uma mão curta para uma restrição de integridade referencial. Eles não fazem parte do modelo relacional. Suponho que você cometeu um erro de digitação.
onedaywhen
7
@ Kenny Muitas vezes sim, mas às vezes um modelo melhor custa mais. Caso em questão: chaves estrangeiras causam mais processamento, não menos.
Hans
8
chaves estrangeiras fazer melhorar o desempenho, pelo menos em MySQL. Além disso, você está certo, a criação de um FK não cria um índice; a criação de uma FK requer um índice
Félix Gagnon-Grenier
15
Essa resposta é praticamente inútil porque não responde à pergunta. É ótimo saber que as chaves estrangeiras não pretendem ter um efeito (positivo) no desempenho, mas a questão era relativa à realidade, não às intenções.
John John
58

Chaves estrangeiras podem melhorar (e prejudicar) o desempenho

  1. Conforme declarado aqui: Chaves estrangeiras aumentam o desempenho

  2. Você sempre deve criar índices nas colunas do FK para reduzir as pesquisas. O SQL Server não faz isso automaticamente.

Editar

Como o link agora parece estar inoperante (parabéns a Chris por perceber) , a seguir mostra a essência do motivo pelo qual as chaves estrangeiras podem melhorar (e prejudicar) o desempenho.

A chave estrangeira pode melhorar o desempenho

A restrição de chave estrangeira melhora o desempenho no momento da leitura dos dados, mas, ao mesmo tempo, diminui o desempenho no momento da inserção / modificação / exclusão de dados.

No caso de ler a consulta, o otimizador pode usar restrições de chave estrangeira para criar planos de consulta mais eficientes, pois as restrições de chave estrangeira são regras pré-declaradas. Isso geralmente envolve pular alguma parte do plano de consulta porque, por exemplo, o otimizador pode ver que, devido a uma restrição de chave estrangeira, é desnecessário executar essa parte específica do plano.

Lieven Keersmaekers
fonte
3
Aqui está um link que detalha maneiras pelas quais eles podem degradar o desempenho devx.com/getHelpOn/10MinuteSolution/16595/0/page/2
cmsjr
3
Isso faz sentido, mas você só encontrará isso com uma declaração de exclusão massiva. Talvez a conclusão deva ser que, em ambientes OLAP, os FKs não indexados melhorariam o desempenho, enquanto nos ambientes OLTP, degradariam o desempenho.
Lieven Keersmaekers # 03/02/09
1
O link nesta resposta está morto. Isso é lamentável, pois é o único argumento aqui para os FKs melhorarem o desempenho.
Chris Moschini
1
@ ChrisMoschini - Eu não notei seu comentário até agora. Como você mencionou, o link está morto, mas a essência dele é mencionada no novo link (com detalhes) que eu postei.
Lieven Keersmaekers
2
Link do Wayback Machine para a vitória! O artigo também pode ser encontrado em SQLMag.com, aqui .
John Eisbrener
15

Uma chave estrangeira é um conceito de DBMS para garantir a integridade do banco de dados.

Quaisquer implicações / melhorias de desempenho serão específicas da tecnologia do banco de dados utilizada e são secundárias ao objetivo de uma chave estrangeira.

É uma boa prática no SQL Server garantir que todas as chaves estrangeiras tenham pelo menos um índice não clusterizado.

Espero que isso esclareça tudo, mas não hesite em solicitar mais detalhes.

John Sansom
fonte
9
@Kenny Evitt, se você não tem integridade, seus dados são inúteis. Acho que vende com muita facilidade.
HLGEM
@HLGEM Obter um erro 404 de vez em quando ainda é bastante suportável. Com rendimento excepcional em troca, usando recursos mais baratos e sistemas menos complexos, agora também é vendido com muita facilidade. Você pode estar interessado no teorema da PAC .
Daniel Dinnyes 19/10/11
8
@ Daniel Dinnyes, a integridade dos dados não se trata de obter um erro 404. É sobre ter dados utilizáveis. Trata-se de não perder pedidos e dados financeiros de relatórios, por exemplo, devido à incompetência dos desenvolvedores. Não há desculpa por não usar chaves estrangeiras.
HLGEM 19/10/11
2
Eu concordo com o HLGEM. Deixar seu código lidar com a integridade nem sempre é uma boa idéia. Os dados geralmente são usados ​​para tomar decisões, mas se os dados estiverem corrompidos, a decisão não será precisa.
Lepe
1
"Chaves estrangeiras são uma ferramenta de integridade relacional" - use a palavra 'relacional' com cuidado. Chaves estrangeiras são um conceito de banco de dados, uma mão curta para uma restrição de integridade referencial. Eles não fazem parte do modelo relacional. Suponho que você cometeu um erro de digitação.
onedaywhen
4

Sua melhor aposta de desempenho é usar índices nos campos que você usa com frequência. Se você usa o SQL Server, pode usar o criador de perfil para criar um perfil em um banco de dados específico, pegar o arquivo que sai e usar o assistente de ajuste para receber recomendações sobre onde colocar seus índices. Também gosto de usar o profiler para liberar procedimentos armazenados de longa execução, tenho uma lista dos dez piores criminosos que publico todas as semanas, mantém as pessoas honestas: D.

Al Katawazi
fonte
3

Você pode usá-lo para ajudar a tornar uma consulta mais eficiente. Ele permite que você reestruture as consultas no SQL Server para usar uma associação externa em vez de uma interna, o que remove a necessidade de servidores sql de verificar se há um nulo na coluna. Você não precisa inserir esse qualificador porque o relacionamento de chave estrangeira já o impõe.

Então, é isso:

    select p.ProductId, p.Name, c.CategoryId, c.Name AS Category 
from Products p inner join ProductCategories c on p.CategoryId = c.CategoryIdwhere c.CategoryId = 1;

Torna-se isso:

SELECT p.ProductId, p.Name, c.CategoryId, c.Name AS Category 
FROM ProductCategories c 
LEFT OUTER JOIN Products P ON
c.CategoryId = p.CategoryId 
WHERE c.CategoryId = 1;

Isso não necessariamente terá um desempenho enorme em consultas pequenas, mas quando as tabelas aumentam, pode ser mais eficiente.

kemiller2002
fonte
3
As uniões externas não são apenas tipicamente menos eficientes do que as uniões internas ( stackoverflow.com/a/2726683/155892 ), agora suas consultas são enganosas: você conta com o banco de dados para transformar implicitamente suas uniões externas em uniões internas (restaurando o desempenho) em vez de apenas fazer isso explicitamente
Mark Sowul
2

Para o MySQL 5.7, ele definitivamente pode acelerar consultas envolvendo várias associações incrivelmente bem!

Usei o 'explicar' para entender minha consulta e descobri que estava juntando 4-5 tabelas - onde nenhuma chave era usada. Não fiz nada além de adicionar uma chave estrangeira a essas tabelas e o resultado foi uma redução de 90% no tempo de carregamento. As consultas que demoraram> 5s agora levam 500 ms ou menos.

Essa é uma melhoria ENORME!

E, como outros já mencionaram, você recebe o bônus adicional de garantir a integridade relacional.

Além disso, garantir a integridade referencial também traz seus próprios benefícios de desempenho. Ele tem o efeito de segunda ordem de garantir que as tabelas que possuem a chave estrangeira estejam 'atualizadas' com a tabela estrangeira. Digamos que você tenha uma tabela de usuários e uma tabela de comentários e faça algumas estatísticas na tabela de comentários. Provavelmente, se você excluir o usuário com força, também não deseja mais os comentários dele.

Peter Bartlett
fonte
As tabelas tinham os índices necessários para gerar as chaves estrangeiras antes de adicioná-las?
George
1

Adicionar uma chave estrangeira na tabela não melhorará o desempenho; basta dizer que, se você estiver inserindo um registro em um banco de dados da tabela ProductCategories, tentará descobrir que a coluna da chave estrangeira tem um valor que existe no valor da chave primária da tabela de produtos. A operação está sobrecarregada no banco de dados toda vez que você adiciona uma nova entrada na tabela ProductCategories. Portanto, adicionar uma chave estrangeira não melhorará o desempenho do banco de dados, mas cuidará da integridade do banco de dados. Sim, ele melhorará o desempenho do seu banco de dados se você estiver verificando a integridade usando chave estrangeira, em vez de executar muitas consultas para verificar se o registro existe no banco de dados do seu programa.

Pankaj Khairnar
fonte
0

Não sei muito sobre o servidor SQL, mas no caso do Oracle, ter uma coluna de chave estrangeira reduz o desempenho do carregamento de dados. Isso ocorre porque o banco de dados precisa verificar a integridade dos dados para cada inserção. E sim, como já foi mencionado, ter um índice na coluna de chave estrangeira é uma boa prática.

Shamik
fonte