Chave primária da tabela muitos-para-muitos

125

Esta pergunta surge depois de ler um comentário nesta pergunta:

Design do Banco de Dados

Ao criar uma tabela muitos-para-muitos, você deve criar uma chave primária composta nas duas colunas de chave estrangeira ou criar uma chave primária "ID" substituta automática de incremento automático e apenas colocar índices nas duas colunas FK (e talvez uma restrição única)? Quais são as implicações no desempenho para inserir novos registros / reindexação em cada caso?

Basicamente, isso:

PartDevice
----------
PartID (PK/FK)
DeviceID (PK/FK)

vs. isto:

PartDevice
----------
ID (PK/auto-increment)
PartID (FK)
DeviceID (FK)

O comentarista diz:

tornar os dois IDs o PK significa que a tabela está classificada fisicamente no disco nessa ordem. Portanto, se inserirmos (Parte1 / Dispositivo1), (Parte1 / Dispositivo2), (Parte2 / Dispositivo3), (Parte 1 / Dispositivo3), o banco de dados terá que dividir a tabela e inserir a última entre as entradas 2 e 3. Para Em muitos registros, isso se torna muito problemático, pois envolve o embaralhamento de centenas, milhares ou milhões de registros toda vez que um é adicionado. Por outro lado, uma PK com incremento automático permite que os novos registros sejam alinhados até o final.

A razão pela qual estou perguntando é porque sempre fui inclinado a executar a chave primária composta sem a coluna de auto incremento substituto, mas não tenho certeza se a chave substituta é realmente mais eficiente.

Andy White
fonte
Aqui está uma pergunta silimar publicado de SO: stackoverflow.com/questions/344068/...
Tony
(Tentei adicionar isso ao meu comentário anterior, mas não posso) Dependendo do número de inserções, você também pode recriar periodicamente seu índice para garantir que ele retorne resultados rapidamente. No SQL Server, você também pode ajustar o FILLFACTOR do índice para fornecer espaço suficiente para inserções antes que ele precise mover dados.
Tony
1
A resposta para isso não depende de qual DBMS é usado? Eu suspeito que o MySQL se comportará de uma maneira neste caso, o SQL-Server levemente de outra maneira etc. #
Radu Murzea
Advertência: Sem uma tag específica do banco de dados, muito do que é dito aqui é suspeito. Motores diferentes funcionam de maneira diferente!
Rick James

Respostas:

85

Com um simples mapeamento de muitos para muitos de duas colunas, não vejo vantagem real em ter uma chave substituta. Ter uma chave primária ativada (col1,col2)é garantida exclusiva (assumindo que seus col1e col2valores nas tabelas referenciadas são exclusivos) e um índice separado em(col2,col1) capturará os casos em que a ordem oposta seria executada mais rapidamente. O substituto é um desperdício de espaço.

Você não precisará de índices nas colunas individuais, pois a tabela só deve ser usada para unir as duas tabelas referenciadas.

Esse comentário a que você se refere na pergunta não vale os elétrons que usa, na minha opinião. Parece que o autor acha que a tabela está armazenada em uma matriz, em vez de uma estrutura em árvore de múltiplas vias equilibrada de desempenho extremamente alto.

Para começar, nunca é necessário armazenar ou obter a tabela classificada, apenas o índice. E o índice não será armazenado sequencialmente, será armazenado de maneira eficiente para poder ser recuperado rapidamente.

Além disso, a grande maioria das tabelas de banco de dados é lida com muito mais frequência do que escrita. Isso torna qualquer coisa que você faz no lado selecionado muito mais relevante do que qualquer coisa no lado da inserção.

paxdiablo
fonte
O último ponto não é uma boa generalização: "a grande maioria das tabelas de banco de dados é lida com muito mais frequência do que escrita". Eu encontro muitos exemplos de tabelas associativas que precisam ser gravadas com muita frequência, por exemplo, uma tabela que liga o cliente ao pedido.
usuário
5
@ Bufer, vou manter esse comentário (tecnicamente, é uma generalização apenas se eu disser "todas as tabelas", "grande maioria" é baseada na experiência). Vamos pensar também no seu exemplo: um pedido é criado uma vez (pode ser atualizado ocasionalmente, mas é improvável que você altere as informações da chave / índice, mais para obter coisas como status do pedido. No entanto, essas atualizações e as seleções que você precisará fazer para imprimir faturas ou gerar relatórios de gerenciamento superará o inserto original #
2177
Pense na Amazon - milhares de pedidos criados a cada hora.
usuário
9
@buffer, sim, mas novamente, cada um desses pedidos quase certamente será consultado muitas vezes para fazer (por exemplo) empacotamento, cobrança, atualizações de status, análises de negócios e assim por diante. O número absoluto de criações é menos importante que a proporção entre cria e lê.
precisa
1
O que quero dizer é insertque importa se isso é feito milhares de vezes por hora. Você não pode simplesmente ignorá-lo apenas porque a proporção de insertpara selecté <1. Nesse caso, um cliente se preocupa com quanto tempo leva para fazer um pedido.
usuário
19

Nenhuma chave substituta é necessária para tabelas de links.

Um PK ativado (col1, col2) e outro índice exclusivo (col2, col1) é tudo o que você precisa

A menos que você use um ORM que não possa lidar e dite o design do seu banco de dados para você ...

Edit: Eu respondi o mesmo aqui: SQL: Você precisa de uma chave primária auto-incremental para tabelas Many-Many?

gbn
fonte
3
Você pode estar bem com um índice de dups no col2, em vez de um índice exclusivo no (col2, col1). A vantagem do índice de duas colunas é que ele permite varreduras somente de índice em col2 sozinho ou em col1 e col2 (embora o outro índice, em (col1, col2) também lide com o caso 'both'). A desvantagem é o armazenamento extra necessário para a coluna extra. Isso geralmente não é significativo, portanto, o conselho está longe de ser terrível. No entanto, se col1 e col2 forem grandes ou de tamanhos muito diferentes, você poderá economizar espaço sem prejudicar o desempenho ao optar por ter o segundo índice apenas na coluna mais curta.
Jonathan Leffler
@gbn: O segundo índice em (col2, col1) não precisa ser único, certo?
usuário
1
colocando um índice exclusivo em (col1, col2) depois que ele já é um PK é totalmente redundante
Don Cheadle
@mmcrae: onde estamos fazendo isso?
GBN
2
@mmcrae: Seu comentário é "colocando um índice exclusivo em (col1, col2) ..". A ordem das colunas em um índice é importante. (col2, col1)não é (col1, col2). A PK de (col1, col2)pode não ser adequada para todas as consultas e gerar varreduras, portanto, o inverso disso melhora o desempenho, pois permite buscas onde col2 é melhor. Por exemplo, validação FK quando a tabela com col2 tiver uma exclusão. A tabela filho smuts ser verificada
gbn 7/11/14
12

Uma chave primária incremental pode ser necessária se a tabela for referenciada. Pode haver detalhes na tabela muitos-para-muitos que precisavam ser extraídos de outra tabela usando a chave primária incremental.

por exemplo

PartDevice
----------
ID (PK/auto-increment)
PartID (FK)
DeviceID (FK)
Other Details

É fácil extrair os 'Outros detalhes' usando PartDevice.ID como o FK. Portanto, é necessário o uso de chave primária incremental.

Jronny
fonte
1
Obrigado! Cheguei à resposta, pois estava procurando quase o mesmo cenário que você descreveu. Mas você se afastou da sua primeira frase adicionando "Outros detalhes". E se eu tivesse uma tabela de mapeamento de muitos para muitos, à qual preciso fazer referência a partir de outra tabela? Ou seja, a tabela de mapeamento de muitos para muitos não armazenou nenhuma outra informação ... A coluna de ID adicional faria sentido? Caso contrário, como fazer referência a um registro da tabela de mapeamento?
Misanthrop
Existem duas opções aqui: você pode usar a chave composta como uma chave estrangeira da sua tabela de referência (isso adiciona uma coluna extra à sua nova tabela) ou pode criar uma coluna de identificação na tabela de mapeamento e definir restrições exclusivas ao composto original. chave primária enquanto a nova coluna de ID se tornará a chave primária.
Vočko 17/09/19
6

A maneira mais curta e direta de responder à sua pergunta é dizer que haverá um impacto no desempenho se as duas tabelas vinculadas não tiverem chaves primárias sequenciais. Como você declarou / citado, o índice da tabela de links se fragmentará ou o DBMS trabalhará mais para inserir registros se a tabela de links não tiver sua própria chave primária seqüencial. Esse é o motivo pelo qual a maioria das pessoas coloca uma chave primária de incremento sequencial nas tabelas de links.

Bernhard Hofmann
fonte
2

Portanto, parece que se o ÚNICO trabalho for vincular as duas tabelas, o melhor PK seria o PK de coluna dupla.

Porém, se isso servir a outros propósitos, adicione outro NDX como um PK com chaves estrangeiras e um segundo índice exclusivo.

Índice ou PK é a melhor maneira de garantir que não haja duplicatas. O PK permite que ferramentas como o Microsoft Management Studio façam parte do trabalho (criando visualizações) para você

Michael Kosak
fonte