Mysql
 sql >> Base de données >  >> RDS >> Mysql

Schéma de base de données déroutant (Index et Contraintes)

Je préférerais la deuxième approche. En utilisant des numéros d'identification de substitution lorsqu'ils ne sont pas logiquement nécessaires à l'identification, vous introduisez davantage de jointures obligatoires. Cela vous oblige à "chasser les numéros d'identification dans toute la base de données", ce qui est l'équivalent SQL de "chasser les pointeurs dans toute la base de données". La chasse aux pointeurs était caractéristique d'IMS, l'une des architectures de base de données que le modèle relationnel entendait remplacer. (IMS utilise une architecture hiérarchique.) Il ne sert à rien de le réinventer aujourd'hui. (Bien que beaucoup des gens font exactement cela.)

Si vous avez, par exemple, cinq niveaux de numéros d'identification de substitution et que vous voulez le nom d'une personne, vous devez faire quatre jointures pour l'obtenir. En utilisant la deuxième approche, vous n'avez besoin que d'une seule jointure. Si vous ne voulez pas écrire de jointures multi-colonnes, utilisez CREATE VIEW et faites-le une seule fois.

Les performances sont simples à tester . Générez simplement quelques millions de lignes aléatoires à l'aide de votre langage de script préféré et chargez-les dans un serveur de test. Vous ne trouverez pas seulement où se cachent vos problèmes de performances, vous trouverez toutes les erreurs dans votre code CREATE TABLE. (Votre code ne fonctionnera pas tel quel.) En savoir plus sur EXPLAIN si vous ne le savez pas déjà.

En ce qui concerne l'indexation , vous pouvez tester cela sur les lignes aléatoires que vous générez et chargez. Un index multi-colonnes sur (first_name, last_name) fonctionnera mieux si les utilisateurs fournissent toujours un prénom. Mais beaucoup d'utilisateurs ne le feront pas, préférant rechercher par nom de famille à la place. Un index multi-colonnes sur (first_name, last_name) n'est pas efficace pour les utilisateurs qui préfèrent rechercher par nom de famille. Vous pouvez tester cela.

Pour cette seule raison, l'indexation des prénoms et des noms de famille est généralement plus efficace s'il y a deux index séparés, un pour le prénom et un pour le nom.

Qu'est-ce que la chasse aux numéros d'identification veux dire ?

Le modèle de conception tacite sous-jacent à cette question est "Chaque ligne doit avoir un numéro d'identification, et toutes les clés étrangères doivent faire référence au numéro d'identification." Dans une base de données SQL, c'est en fait un anti-modèle. En règle générale, tout modèle qui vous permet de concevoir des tables sans penser aux clés doit être présumé coupable jusqu'à preuve du contraire. Il doit être présumé être un anti-modèle jusqu'à ce qu'il soit prouvé qu'il ne l'est pas.

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)
);

Si vous avez besoin d'un rapport sur le tableau "D", et que le rapport a besoin de

  • colonnes D.d_1 et D.d_2, et
  • colonnes A.a_1 et A.a_2,

vous avez besoin de 3 jointures pour y accéder. (Essayez-le.) Vous cherchez des numéros d'identification. (Comme la chasse aux pointeurs dans IMS.) La structure suivante est différente.

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)
);

Avec cette structure, le même rapport nécessite une seule jointure.

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;