Surrogate vs chave natural: números concretos sobre as diferenças de desempenho?
-
22-07-2019 - |
Pergunta
Há um debate saudável lá fora, entre aluguel e chaves naturais:
A minha opinião, que parece estar em linha com a maioria (é uma pequena maioria), é que você deve usar chaves substitutas menos que uma chave natural é completamente óbvia e garantia de não mudança. Então você deve impor a exclusividade na chave natural. Que meios substituto chaves quase todo o tempo.
Exemplo das duas abordagens, começando com uma tabela Empresa:
1: chave substituta: Table tem um campo de ID que é a PK (e uma identidade). nomes de empresas são obrigados a ser único em cada estado, por isso há uma restrição exclusiva lá.
2: chave Natural:. Tabela usa CompanyName e Estado como o PK - satisfaça tanto o PK e singularidade
Vamos dizer que o PK Empresa é usada em outros 10 mesas. Minha hipótese, sem números para apoiá-la, é que a abordagem chave substituta seria muito mais rápido aqui.
O argumento só convencer que eu vi para a chave natural é de muitos para muitos tabela que usa as duas chaves estrangeiras como uma chave natural. Eu acho que, nesse caso, faz sentido. Mas você pode ter problemas se você precisa refatorar; que está fora do escopo deste post eu acho.
Alguém viu um artigo que compara diferenças desempenho em um conjunto de tabelas que usam chaves substitutas vs. o mesmo conjunto de tabelas usando chaves naturais ? Olhando ao redor no SO e Google não produziu qualquer coisa de valor, apenas um monte de theorycrafting.
Atualização Importante : Eu comecei a construir um conjunto de tabelas de teste que a resposta a esta pergunta. Parece que este:
- PartNatural - peças tabela que usa o PartNumber único como um PK
- PartSurrogate - peças tabela que utiliza um ID (int, identidade) como PK e tem um índice exclusivo na PartNumber
- Plant - ID (int, identidade) como PK
- Engineer - ID (int, identidade) como PK
Cada parte é ligada a uma planta e cada instância de uma peça de cada planta é unido a um engenheiro. Se alguém tem um problema com este testbed, agora é a hora.
Solução
Use ambos! Chaves naturais impedir a corrupção de banco de dados (inconsistência pode ser uma palavra melhor). Quando a chave natural "direito", (para eliminar linhas duplicadas) iria executar mal por causa do comprimento, ou o número de colunas envolvidas, para fins de desempenho, uma chave substituta podem ser adicionados, assim como para ser usado como chaves estrangeiras em outras tabelas em vez de a chave natural ... Mas a chave natural deve permanecer como uma chave alternativa ou índice exclusivo para evitar a corrupção de dados e banco de dados enforece consistência ...
A maior parte da hoohah (no "debate" sobre esta questão), pode ser devido a que é uma suposição falsa - que você tem que usar o chave primária para junta e chaves estrangeiras em outras tabelas. ISTO É FALSO. Você pode usar qualquer tecla de como o destino para as chaves estrangeiras em outras tabelas. Ele pode ser a chave primária, uma chave alternativa, ou qualquer índice único ou restrição única. E quanto a junta, você pode usar qualquer coisa para uma condição de junção, não tem sequer a ser uma chave, ou um idex, ou mesmo única !! (Embora se não é único você vai ter várias linhas no produto cartesiano ele cria).
Outras dicas
chaves naturais diferem das chaves substitutas em valor, não digite.
Qualquer tipo pode ser usado para uma chave substituta, como uma VARCHAR
para o slug
gerado pelo sistema ou qualquer outra coisa.
No entanto, os tipos mais usados ??para chaves substitutas são INTEGER
e RAW(16)
(ou o que digitar sua RDBMS
faz uso para GUID
de),
Comparando inteiros substitutos e inteiros naturais (como SSN
) leva exatamente mesmo tempo.
VARCHAR
s Comparando fazer take agrupamento em conta e eles são geralmente mais do que números inteiros, que tornando-os menos eficientes.
Comparando um conjunto de dois INTEGER
provavelmente também é menos eficiente do que a comparação de um único INTEGER
.
Por tipos de dados pequenos em tamanho dessa diferença é provavelmente percentuais de porcentagens do tempo necessário para buscar páginas, índices transversal, base de dados acquite travas etc.
E aqui estão os números (em MySQL
):
CREATE TABLE aint (id INT NOT NULL PRIMARY KEY, value VARCHAR(100));
CREATE TABLE adouble (id1 INT NOT NULL, id2 INT NOT NULL, value VARCHAR(100), PRIMARY KEY (id1, id2));
CREATE TABLE bint (id INT NOT NULL PRIMARY KEY, aid INT NOT NULL);
CREATE TABLE bdouble (id INT NOT NULL PRIMARY KEY, aid1 INT NOT NULL, aid2 INT NOT NULL);
INSERT
INTO aint
SELECT id, RPAD('', FLOOR(RAND(20090804) * 100), '*')
FROM t_source;
INSERT
INTO bint
SELECT id, id
FROM aint;
INSERT
INTO adouble
SELECT id, id, value
FROM aint;
INSERT
INTO bdouble
SELECT id, id, id
FROM aint;
SELECT SUM(LENGTH(value))
FROM bint b
JOIN aint a
ON a.id = b.aid;
SELECT SUM(LENGTH(value))
FROM bdouble b
JOIN adouble a
ON (a.id1, a.id2) = (b.aid1, b.aid2);
t_source
é apenas uma tabela fictícia com linhas 1,000,000
.
aint
e adouble
, bint
e bdouble
conter exactamente os mesmos dados, excepto que aint
tem um inteiro como um PRIMARY KEY
, enquanto adouble
tem um par de dois inteiros iguais.
Na minha máquina, ambas as consultas funcionam por 14,5 segundos, +/- 0,1 segundos
Diferença de desempenho, se houver, está dentro das flutuações variar.