Mysql
 sql >> Base de Dados >  >> RDS >> Mysql

Esquema de banco de dados confuso (índice e restrições)


Eu preferiria a segunda abordagem. Ao usar números de ID substitutos quando eles não são logicamente necessários para identificação, você introduz mais junções obrigatórias. Isso requer que você "persegue números de ID por todo o banco de dados", que é o equivalente SQL a "perseguir ponteiros por todo o banco de dados". A busca por ponteiros era característica do IMS, uma das arquiteturas de banco de dados que o modelo relacional pretendia substituir. (O IMS usa uma arquitetura hierárquica.) Não faz sentido reinventá-lo hoje. (Embora um muito das pessoas fazem exatamente isso.)

Se você tiver, por exemplo, cinco níveis de números de identificação substitutos e quiser o nome de uma pessoa, precisará fazer quatro junções para obtê-lo. Usando a segunda abordagem, você só precisa de uma junção. Se você não quiser escrever junções de várias colunas, use CREATE VIEW e faça isso apenas uma vez.

O desempenho é simples de testar . Basta gerar alguns milhões de linhas aleatórias usando sua linguagem de script favorita e carregá-las em um servidor de teste. Você não apenas descobrirá onde seus problemas de desempenho estão se escondendo, mas também todos os erros em seu código CREATE TABLE. (Seu código não funcionará como está.) Saiba mais sobre EXPLAIN se você ainda não sabe disso.

Quanto à indexação , você pode testar isso nas linhas aleatórias que você gera e carrega. Um índice de várias colunas em (first_name, last_name) funcionará melhor se os usuários sempre fornecerem um primeiro nome. Mas muitos usuários não fazem isso, preferindo pesquisar pelo sobrenome. Um índice de várias colunas em (first_name, last_name) não é eficaz para usuários que preferem pesquisar pelo sobrenome. Você pode testar isso.

Por esse motivo, a indexação de nomes e sobrenomes é geralmente mais eficaz se houver dois índices separados, um para o primeiro nome e outro para o sobrenome.


O que significa perseguir números de identificação quer dizer?
O padrão de design tácito subjacente a essa pergunta é "Cada linha deve ter um número de identificação e todas as chaves estrangeiras devem fazer referência ao número de identificação". Em um banco de dados SQL, na verdade é um antipadrão. Como regra geral, qualquer padrão que permita projetar tabelas sem pensar em chaves deve ser considerado culpado até que se prove a inocência - deve ser considerado um antipadrão até que se prove que não o é.
create table A (
 a_id integer primary key,
 a_1 varchar(15) not null unique,
 a_2 varchar(15) not null
);

create table B (
  b_id integer primary key
  a_id integer not null references A (a_id),
  b_1  varchar(10) not null,
  unique (a_id, b_1),
);

create table C (
  c_id integer primary key,
  b_id integer not null references B (b_id),
  c_1 char(3) not null,
  c_2 varchar(20) not null,
  unique (b_id, c_1)
);

create table D (
  d_id integer primary key,
  c_id integer not null references C (c_id),
  d_1 integer not null,
  d_2 varchar(15),
  unique (c_id, d_1)
);

Se você precisa de um relatório na tabela "D", e o relatório precisa
  • colunas D.d_1 e D.d_2 e
  • colunas A.a_1 e A.a_2,

você precisa de 3 junções para chegar a ele. (Experimente.) Você está perseguindo números de identificação. (Como perseguir ponteiros no IMS.) A estrutura a seguir é diferente.
create table A (
 a_1 varchar(15) primary key,
 a_2 varchar(15) not null
);

create table B (
  a_1 varchar(15) not null references A (a_1),
  b_1  varchar(10) not null,
  primary key (a_1, b_1),
);

create table C (
  a_1 varchar(15) not null,
  b_1 varchar(10) not null,
  c_1 char(3) not null,
  c_2 varchar(20) not null,
  primary key (a_1, b_1, c_1),
  foreign key (a_1, b_1) references B (a_1, b_1)
);

create table D (
  a_1 varchar(15) not null,
  b_1 varchar(10) not null,
  c_1 char(3) not null,
  d_1 integer not null,
  d_2 varchar(15),
  primary key (a_1, b_1, c_1, d_1),
  foreign key (a_1, b_1, c_1) references C (a_1, b_1, c_1)
);

Com essa estrutura, o mesmo relatório precisa de uma única junção.
select D.d_1, D.d_2, A.a_1, A.a_2
from D
inner join A on D.a_1 = A.a_1;