Chave primária ou índice exclusivo?

127

No trabalho, temos um grande banco de dados com índices exclusivos em vez de chaves primárias e tudo funciona bem.

Estou criando um novo banco de dados para um novo projeto e tenho um dilema:

Na teoria do banco de dados, a chave primária é o elemento fundamental, tudo bem, mas nos projetos REAL, quais são as vantagens e desvantagens de ambos?

O que você usa nos projetos?

EDIT: ... e o que dizer de chaves primárias e replicação no servidor MS SQL?

Cicik
fonte
2
Existem algumas considerações adicionais discutidas aqui (embora com o contexto adicional de um índice de cobertura) - dba.stackexchange.com/questions/21554/...
StuartLC
NOTA: O SQLite é diferente, pois permite que a chave primária seja nula, contra o padrão comum devido a um problema herdado. sqlite.org/lang_createtable.html
bitinn 10/10

Respostas:

168

O que é um índice exclusivo?

Um índice exclusivo em uma coluna é um índice nessa coluna que também impõe a restrição de que você não pode ter dois valores iguais nessa coluna em duas linhas diferentes. Exemplo:

CREATE TABLE tabela1 (foo int, bar int);
CRIAR ÍNDICE ÚNICO ux_table1_foo ON table1 (foo); - Crie um índice exclusivo no foo.

INSERIR NA tabela1 (foo, bar) VALORES (1, 2); -- ESTÁ BEM
INSERIR NA tabela1 (foo, bar) VALORES (2, 2); -- ESTÁ BEM
INSERIR NA tabela1 (foo, bar) VALORES (3, 1); -- ESTÁ BEM
INSERIR NA tabela1 (foo, bar) VALORES (1, 4); - Falha!

Entrada duplicada '1' para a chave 'ux_table1_foo'

A última inserção falha porque viola o índice exclusivo na coluna fooquando tenta inserir o valor 1 nessa coluna pela segunda vez.

No MySQL, uma restrição exclusiva permite vários NULLs.

É possível criar um índice exclusivo em colunas múltiplas.

Chave primária versus índice exclusivo

Coisas iguais:

  • Uma chave primária implica um índice exclusivo.

Coisas diferentes:

  • Uma chave primária também implica NOT NULL, mas um índice exclusivo pode ser anulável.
  • Pode haver apenas uma chave primária, mas pode haver vários índices exclusivos.
  • Se não houver um índice em cluster definido, a chave primária será o índice em cluster.
Mark Byers
fonte
4
Observe que um índice exclusivo é um índice em uma coluna que não é totalmente preciso, pois um índice exclusivo ou chave primária pode incluir mais de uma coluna.
Alex Jasmin
2
@Alexandre Jasmin: Corrigido obrigado. A parte sobre várias colunas é mencionada mais tarde.
Mark Byers
Com referência a nulos, os padrões da ansi permitem vários valores nulos em um conjunto de dados com uma restrição exclusiva, e essa também é a implementação no Oracle e PostgreSQL. Acredito que o SQL Server permita apenas um valor nulo.
David Aldridge
3
mas ainda não entendi, como quando usar chave primária ou quando usar índice exclusivo? ou pode ser ambos nas mesmas situações.
Amit
33

Você pode vê-lo assim:

Uma chave primária é única

Um valor exclusivo não precisa ser a representação do elemento

Significado?; Bem, uma chave primária é usada para identificar o elemento, se você tem uma "Pessoa", você gostaria de ter um Número de Identificação Pessoal (SSN ou similar) que seja Primário para sua Pessoa.

Por outro lado, a pessoa pode ter um e-mail exclusivo, mas não a identifica.

Eu sempre tenho Chaves Primárias, mesmo em tabelas de relacionamento (a tabela intermediária / de conexão) eu posso tê-las. Por quê? Bem, eu gosto de seguir um padrão ao codificar, se a "Pessoa" tiver um identificador, o Carro tiver um identificador, bem, a Pessoa -> Carro também deverá ter um identificador!

Filip Ekberg
fonte
Em suas tabelas de relacionamento: você quer dizer que introduz uma nova coluna com uma chave primária artificial (um número inteiro, por exemplo) ou usa uma chave primária composta (person_id, car_id)?
3
chave primária (person_id, car_id) seria a melhor. Mas geralmente crio uma nova coluna, com certeza isso gera alguma sobrecarga, mas considerei bom. Você nunca sabe se deseja se relacionar com uma relação específica em um cenário posterior.
Filip Ekberg
1
A outra coisa que a chave primária substituta faz na sua tabela de junção / composição é facilitar a manutenção de tarefas manuais.
22380 Robert C. Barth
2
Você só precisa de uma chave primária se quiser ter filhos. Por que adicionar uma coluna e uma sequência se o valor não aparecer em lugar algum, se o valor for usado para nada? É make-work para impedir que o Access solicite um PK. Faça um PK se precisar identificar o registro em uma criança, caso contrário é um desperdício.
3
Se não tem nada a ver com relações, o que tem a ver? Você aponta para um campo e diz que é primário. E? Então o que acontece? E se não houver pk natural, adiciono uma coluna e uma sequência e um gatilho e tudo porque ____? Alguns só precisam ser primários. Eu evito regras sem motivos.
10

Chaves estrangeiras funcionam com restrições exclusivas e chaves primárias. Dos Livros Online:

Uma restrição FOREIGN KEY não precisa ser vinculada apenas a uma restrição PRIMARY KEY em outra tabela; também pode ser definido para referenciar as colunas de uma restrição UNIQUE em outra tabela

Para replicação transacional, você precisa da chave primária. Dos Livros Online:

As tabelas publicadas para replicação transacional devem ter uma chave primária. Se uma tabela estiver em uma publicação de replicação transacional, você não poderá desativar nenhum índice associado a colunas de chave primária. Esses índices são necessários por replicação. Para desabilitar um índice, você deve primeiro remover a tabela da publicação.

Ambas as respostas são para o SQL Server 2005.

Jonas Lincoln
fonte
Isso me assusta muito (primeira citação). Por quê? Eu tenho uma tabela de pessoa com um ID arbitrário que é o meu PK, mas decido adicionar um Reino Unido ao Telefone, E-mail e SSN ... então agora quatro tabelas diferentes se juntam à pessoa em quatro colunas diferentes? Acho que abriria mão de qualquer flexibilidade que você possa obter por consistência.
5

A escolha de quando usar uma chave primária substituta em oposição a uma chave natural é complicada. Respostas como, sempre ou nunca, raramente são úteis. Acho que depende da situação.

Como exemplo, eu tenho as seguintes tabelas:

CREATE TABLE toll_booths (
    id            INTEGER       NOT NULL PRIMARY KEY,
    name          VARCHAR(255)  NOT NULL,
    ...
    UNIQUE(name)
)

CREATE TABLE cars (
    vin           VARCHAR(17)   NOT NULL PRIMARY KEY,
    license_plate VARCHAR(10)   NOT NULL,
    ...
    UNIQUE(license_plate)
)

CREATE TABLE drive_through (
    id            INTEGER       NOT NULL PRIMARY KEY,
    toll_booth_id INTEGER       NOT NULL REFERENCES toll_booths(id),
    vin           VARCHAR(17)   NOT NULL REFERENCES cars(vin),
    at            TIMESTAMP     DEFAULT CURRENT_TIMESTAMP NOT NULL,
    amount        NUMERIC(10,4) NOT NULL,
    ...
    UNIQUE(toll_booth_id, vin)
)

Temos duas tabelas de entidades ( toll_boothse cars) e uma tabela de transações ( drive_through). A toll_boothtabela usa uma chave substituta porque não possui nenhum atributo natural que não garante a alteração (o nome pode ser alterado facilmente). A carstabela usa uma chave primária natural porque possui um identificador exclusivo ( vin) que não muda . A drive_throughtabela de transações usa uma chave substituta para facilitar a identificação, mas também possui uma restrição exclusiva nos atributos que são garantidos como exclusivos no momento em que o registro é inserido.

http://database-programmer.blogspot.com tem ótimos artigos sobre esse assunto em particular.

aekeus
fonte
4

Não há desvantagens de chaves primárias.

Para adicionar apenas algumas informações às respostas @MrWiggles e @Peter Parker, quando a tabela não tiver chave primária, por exemplo, você não poderá editar dados em alguns aplicativos (eles acabarão dizendo que sth como não pode editar / excluir dados sem chave primária). O Postgresql permite que vários valores NULL estejam na coluna UNIQUE, PRIMARY KEY não permite NULLs. Além disso, alguns ORM que geram código podem ter alguns problemas com tabelas sem chaves primárias.

ATUALIZAR:

Tanto quanto sei, não é possível replicar tabelas sem chaves primárias no MSSQL, pelo menos sem problemas ( detalhes ).

empi
fonte
Há sobrecarga quando novas linhas são inseridas ou essa coluna é atualizada.
3

Se algo for uma chave primária, dependendo do mecanismo do banco de dados, a tabela inteira será classificada pela chave primária. Isso significa que as pesquisas são muito mais rápidas na chave primária porque ela não precisa fazer nenhuma referência diferente, como acontece com qualquer outro tipo de índice. Além disso, é apenas teoria.

Ray Hidayat
fonte
3
a tabela será classificada pelo índice de cluster e não necessariamente pela chave primária.
Ray Booysen
1
acontece que a maioria das pessoas define sua chave primária como o índice clusterizado.
Ray Booysen
Que sabemos que é muitas vezes uma ideia muito ruim, a não ser que como hot-spots e árvores índice desequilibradas em nossas mesas, claro ...
Mike Woodhouse
1
Não é sempre uma idéia muito ruim. Conheça seus dados, conheça seu RDBMS, saiba o que as opções significam. Raramente a escolha SEMPRE é boa ou ruim. Se SEMPRE fosse um, o banco de dados o exigiria ou o proibiria. Eles dão a você a escolha porque 'Depende'.
2

Além do que as outras respostas disseram, alguns bancos de dados e sistemas podem exigir a presença de um primário. Uma situação vem à mente; ao usar a replicação corporativa com o Informix, uma PK deve estar presente para que uma tabela participe da replicação.

tddmonkey
fonte
2

Contanto que você não permita NULL para um valor, eles devem ser tratados da mesma forma, mas o valor NULL é tratado de maneira diferente nos bancos de dados (o AFAIK MS-SQL não permite mais de um (1) valor NULL, o mySQL e o Oracle permitem isso , se uma coluna for ÚNICA) Portanto, você deve definir esta coluna NÃO NÚMERO ÍNDICE ÚNICO

Peter Parker
fonte
1
O MS-SQL permite vários valores NULL em uma coluna que possui um índice exclusivo, assim como todo RDBMS. Pense da seguinte maneira: NULL não é um valor; portanto, quando você insere um segundo NULL, ele nunca corresponderá a um existente. A expressão (NULL == NULL) não é avaliada como true ou false, é avaliada como NULL.
gregmac 29/01
thanx gregmac, eu não tinha certeza, se a MS segue isso. Lembrei-me de alguns MS Quirks com isso, no entanto, alguns anos atrás (antes de 2000) e também poderia ser uma tosse
Peter Parker
2

Não existe uma chave primária na teoria dos dados relacionais; portanto, sua pergunta deve ser respondida no nível prático.

Índices exclusivos não fazem parte do padrão SQL. A implementação específica de um DBMS determinará quais são as conseqüências da declaração de um índice exclusivo.

No Oracle, declarar uma chave primária resultará na criação de um índice exclusivo em seu nome, portanto a questão é quase discutível. Não posso falar sobre outros produtos DBMS.

Eu sou a favor de declarar uma chave primária. Isso tem o efeito de proibir NULLs na (s) coluna (s) chave (s), além de proibir duplicatas. Também sou a favor de declarar restrições de REFERENCES para reforçar a integridade da entidade. Em muitos casos, declarar um índice no (s) coulmn (s) de uma chave estrangeira acelerará as junções. Esse tipo de índice geralmente não deve ser único.

Walter Mitty
fonte
Uma chave primária no MS SQL Server sempre é ÚNICA e NÃO NULA - por exemplo, é realmente apenas um índice Exclusivo, mas com a restrição adicional de que não pode ser NULL.
31323 marc_s
A Oracle pode impor uma restrição exclusiva a um índice não exclusivo. Eu ficaria surpreso se o MSSS não pudesse. Dizer "é realmente apenas um índice único" é um desserviço.
"Em muitos casos, declarar um índice no (s) coulmn (s) de uma chave estrangeira acelerará as junções". isso quase sempre não é verdade em um mundo de data warehousing em que as junções de hash seriam preferidas, se disponíveis.
JAC2703
O OP não mencionou armazéns. Não tenho certeza de como os hasins lombos funcionam no servidor sql. Quanto do trabalho pode ser feito no momento da atualização do armazém.
Walter Mitty
2

Existem algumas desvantagens de ÍNDICES CLUSTERED vs ÍNDICES ÚNICOS.

Como já foi dito, um ÍNDICE CLUSTERED solicita fisicamente os dados na tabela.

Isso significa que quando você tem muito se inserir ou excluir uma tabela que contém um índice em cluster, toda vez (bem, quase, dependendo do fator de preenchimento) você altera os dados, a tabela física precisa ser atualizada para permanecer classificada.

Em tabelas relativamente pequenas, isso é bom, mas ao acessar tabelas com dados em GB e inserções / exclusões afetam a classificação, você terá problemas.

Nico Bester
fonte
Qual é a vantagem então? consultas classificadas são mais rápidas? isso é melhor para um caso de uso quando você grava a maioria dos seus dados uma vez (ou raramente) e os consulta o tempo todo?
Buffalo
1

Quase nunca crio uma tabela sem uma chave primária numérica. Se também houver uma chave natural que deva ser única, também coloquei um índice exclusivo. As junções são mais rápidas em números inteiros do que as chaves naturais de várias colunas; os dados precisam apenas ser alterados em um único local (as chaves naturais tendem a precisar ser atualizadas, o que é uma coisa ruim quando se trata de relacionamentos de chave primária - chave estrangeira). Se você precisar de replicação, use um GUID em vez de um número inteiro, mas na maioria das vezes prefiro uma chave legível pelo usuário, especialmente se eles precisarem vê-la para distinguir entre John Smith e John Smith.

As poucas vezes em que não crio uma chave substituta são quando tenho uma tabela de junção envolvida em um relacionamento de muitos para muitos. Nesse caso, declaro os dois campos como a chave primária.

HLGEM
fonte
“Quase nunca crio uma tabela sem uma chave primária numérica”: por que sempre numérica? Uma chave primária não precisa ser numérica (nem precisa ser AUTO_INCREMENT, a propósito).
precisa saber é o seguinte
@ Hinou57, porque descobri que as chaves naturais raramente são únicas e quase sempre são mutáveis. As junções Furthere nos intergers são geralmente muito mais rápidas do que as junções nas chaves naturais varcahrr ou nas chaves compostas piores. Eu não os usaria quase o tempo todo. Isso pode variar de acordo com o tipo de informação que você armazena no seu banco de dados, mas, na minha experiência pessoal, descobri que as chaves naturais são extremamente não confiáveis ​​ao longo do tempo.
HLGEM
Obrigado pela resposta HLGEM. O que você quer dizer com não confiável? Atuação? (Espero que não seja uma questão de confiabilidade no sentido de integridade dos dados). Estou um pouco surpreso com suas palavras, como se eu usasse chaves inteiras ou mais chaves naturais como VARCHAR curto, provavelmente faria uma pequena diferença, pois o hash é usado em qualquer lugar, mesmo com os mecanismos de banco de dados mais simples.
precisa saber é o seguinte
Eles não são confiáveis ​​em muitos casos, porque não são confiáveis ​​de maneira única, embora devessem ser. Eles não são confiáveis ​​porque mudam e podem afetar milhões de registros em uma atualização. Esta é a minha experiência de ter visto e gerenciado ou consultado dados ou importado de centenas de bancos de dados que armazenam dados sobre muitos tipos diferentes de informações.
HLGEM
1

Meu entendimento é que uma chave primária e um índice exclusivo com uma restrição não nula, são os mesmos (*); e suponho que um escolha um ou outro, dependendo do que a especificação declara ou implica explicitamente (uma questão do que você deseja expressar e aplicar explicitamente). Se exigir exclusividade e não nulo, torne-a uma chave primária. Se acontecer que todas as partes de um índice exclusivo não são nulas sem nenhum requisito para isso, basta torná-lo um índice exclusivo.

A única diferença restante é que você pode ter vários índices exclusivos não nulos, enquanto não pode ter várias chaves primárias.

(*) Exceto uma diferença prática: uma chave primária pode ser a chave exclusiva padrão para algumas operações, como definir uma chave estrangeira. Ex. se alguém definir uma chave estrangeira referenciando uma tabela e não fornecer o nome da coluna, se a tabela referenciada tiver uma chave primária, a chave primária será a coluna referenciada. Caso contrário, a coluna referenciada deverá ser nomeada explicitamente.

Outros aqui mencionaram a replicação de banco de dados, mas eu não sei sobre isso.

Hibou57
fonte
0

Índice exclusivo pode ter um valor NULL. Ele cria ÍNDICE NÃO CLUSTERED. Chave primária não pode conter valor NULL. Cria ÍNDICE CLUSTERED.

Chirag
fonte
0

No MSSQL, as chaves primárias devem aumentar monotonicamente para obter o melhor desempenho no índice em cluster. Portanto, um número inteiro com inserção de identidade é melhor do que qualquer chave natural que pode não estar aumentando monotonicamente.

Markus
fonte
-1

Se fosse por mim...

Você precisa atender aos requisitos do banco de dados e de seus aplicativos.

A adição de uma coluna de ID inteiro ou longo com incremento automático a todas as tabelas para servir como chave primária cuida dos requisitos do banco de dados.

Você adicionaria pelo menos um outro índice exclusivo à tabela para uso do seu aplicativo. Esse seria o índice em employee_id, ou account_id, ou customer_id, etc. Se possível, esse índice não deve ser um índice composto.

Eu preferiria índices em vários campos individualmente sobre índices compostos. O banco de dados usará os índices de campo único sempre que a cláusula where incluir esses campos, mas somente usará um composto quando você fornecer os campos exatamente na ordem correta - o que significa que não poderá usar o segundo campo em um índice composto, a menos que você forneça o primeiro e o segundo na sua cláusula where.

Sou a favor do uso de índices calculados ou do tipo Função - e recomendo usá-los sobre índices compostos. Isso facilita muito o uso do índice de função, usando a mesma função na sua cláusula where.

Isso cuida dos requisitos de sua aplicação.

É altamente provável que outros índices não primários sejam realmente mapeamentos desse valor de chave de índices para um valor de chave primária, não para rowid (). Isso permite que operações de classificação física e exclusões ocorram sem a necessidade de recriar esses índices.

Rodney P. Barbati
fonte