web-dev-qa-db-fra.com

Utilisation appropriée des tables de recherche

J'ai du mal à trouver exactement comment placer de bonnes limites pour quand et où utiliser les tables de recherche dans une base de données. La plupart des sources que j'ai consultées disent que je ne peux jamais en avoir trop mais, à un moment donné, il semble que la base de données soit décomposée en tant de morceaux que, même si elle est efficace, elle n'est plus gérable. Voici un exemple de ce avec quoi je travaille:

Disons que j'ai une table appelée Employés:

ID  LName   FName   Gender  Position
1   Doe     John    Male    Manager
2   Doe     Jane    Female  Sales
3   Smith   John    Male    Sales

Imaginez un instant que les données sont plus complexes et contiennent des centaines de lignes. La chose la plus évidente que je vois qui pourrait être déplacée vers une table de recherche serait Position. Je pourrais créer une table appelée Positions et coller les clés étrangères de la table Positions dans la table Employés de la colonne Position.

ID  Position
1   Manager
2   Sales

Mais jusqu'où puis-je continuer de décomposer les informations en tables de recherche plus petites avant qu'elles ne deviennent ingérables? Je pourrais créer une table de genre et avoir 1 correspond à Homme et 2 correspond à Femme dans une table de recherche séparée. Je pourrais même mettre des LNames et FNames dans des tableaux. Toutes les entrées "John" sont remplacées par une clé étrangère de 1 qui pointe vers la table FName qui indique qu'un ID de 1 correspond à John. Si vous descendez trop loin dans ce lapin comme celui-ci, votre table Employés est alors réduite à un désordre de clés étrangères:

ID  LName   FName   Gender  Position
1   1       1       1       1
2   1       2       2       2
3   2       1       1       2

Bien que cela puisse ou non être plus efficace pour un serveur à traiter, cela est certainement illisible pour une personne normale qui essaie de le maintenir et rend plus difficile pour un développeur d'applications essayant d'y accéder. Donc, ma vraie question est de savoir jusqu'où est trop loin? Existe-t-il quelque part des "meilleures pratiques" pour ce genre de choses ou un bon ensemble de directives? Je ne trouve aucune information en ligne qui définit vraiment un bon ensemble de directives utilisables pour ce problème particulier que j'ai. La conception de la base de données est un vieux chapeau pour moi, mais la BONNE conception de la base de données est très nouvelle, donc des réponses trop techniques peuvent être sur ma tête. Toute aide serait appréciée!

25
Brad Turner

Mais jusqu'où puis-je continuer de décomposer les informations en tables de recherche plus petites avant qu'elles ne deviennent ingérables? Je pourrais créer une table de genre et avoir 1 correspond à Homme et 2 correspond à Femme dans une table de recherche séparée.

Vous mélangez deux problèmes différents. Un problème est l'utilisation d'une table de "recherche"; l'autre est l'utilisation de clés de substitution (numéros d'identification).

Commencez avec ce tableau.

ID  LName   FName   Gender  Position
1   Doe     John    Male    Manager
2   Doe     Jane    Female  Sales
3   Smith   John    Male    Sales

Vous pouvez créer une table de "recherche" pour des positions comme celle-ci.

create table positions (
  pos_name varchar(10) primary key
);

insert into positions
select distinct position 
from employees;

alter table employees
add constraint emp_fk1
foreign key (position) 
  references positions (pos_name);

Votre table d'origine ressemble exactement à ce qu'elle était avant de créer la table de "recherche". Et la table des employés ne nécessite aucune jointure supplémentaire pour en tirer des données utiles et lisibles par l'homme.

L'utilisation d'une table de "recherche" se résume à ceci: votre application a-t-elle besoin du contrôle sur les valeurs d'entrée fournies par une référence de clé étrangère? Si c'est le cas, vous pouvez toujours utiliser une table de "recherche". (Qu'il utilise ou non une clé de substitution.)

Dans certains cas, vous pourrez remplir complètement cette table au moment du design. Dans d'autres cas, les utilisateurs doivent pouvoir ajouter des lignes à cette table au moment de l'exécution. (Et vous devrez probablement inclure certains processus administratifs pour examiner les nouvelles données.) Le sexe, qui a en fait un norme ISO , peut être complètement rempli au moment de la conception. Les noms de rue pour les commandes de produits en ligne internationales doivent probablement être ajoutés au moment de l'exécution.

Dans votre table Employés, je n'aurais qu'une recherche de "Position" car il s'agit d'un ensemble limité de données qui peuvent se développer.

  • Le genre est auto-descriptif (disons M ou F), limité à 2 valeurs, et peut être appliqué avec une contrainte CHECK. Vous n'ajouterez pas de nouveaux genres (en ignorant les conneries d'exactitude politique)
  • Le prénom "John" ne fait pas partie d'un ensemble de données limité et restreint: l'ensemble potentiel de données est massif au point d'être illimité, il ne devrait donc pas être une recherche

Si vous souhaitez ajouter une nouvelle position, vous ajoutez simplement une ligne à la table de recherche. Cela supprime également anomalies de modification des données qui est un point de normalisation

De plus, une fois que vous avez un million d'employés, il est plus efficace de stocker tinyint PositionID que varchar.

Ajoutons une nouvelle colonne "devise du salaire". J'utiliserais ici une table de recherche avec une clé de CHF, GBP, EUR, USD, etc.: je n'utiliserais pas de clé de substitution. Cela pourrait être restreint avec une contrainte CHECK comme le genre, mais il s'agit d'un ensemble limité mais extensible de données comme Position. Je donne cet exemple car j'utiliserais la clé naturelle même si elle apparaît dans un million de lignes de données d'employé malgré le caractère char (3) plutôt que tinyint

Donc, pour résumer, vous utilisez des tables de recherche

  1. où vous avez un ensemble de données fini, mais extensible dans une colonne
  2. où est pas auto-décrivant
  3. pour éviter anomalies de modification des données
8
gbn

La réponse est "ça dépend". Pas très satisfaisant mais il y a beaucoup d'influences qui poussent et tirent le design. Si des programmeurs d'applications conçoivent la base de données, une structure comme celle que vous décrivez fonctionne pour eux car l'ORM cache la complexité. Vous vous arracherez les cheveux lorsque vous rédigerez des rapports et devrez rejoindre dix tables pour obtenir une adresse.

Conception pour l'utilisation, l'utilisation prévue et l'utilisation future probable. C'est là que votre connaissance du processus métier entre en jeu. Si vous concevez une base de données pour une entreprise vétérinaire, il existe des hypothèses raisonnables sur la taille, l'utilisation et les directions des fonctionnalités qui seront très différentes d'une start-up de haute technologie.

Pour réutiliser une citation préférée

"Un homme sage m'a dit" normalisez jusqu'à ce que ça fasse mal, dénormalisez jusqu'à ce que ça marche ".

Quelque part, il y a le point idéal. D'après mon expérience, avoir un identifiant de clé dans plus d'une table n'est pas un crime aussi grave que certains le pensent si vous ne changez jamais de clé primaire.

Prenez cet exemple abrégé de tables hautement normalisées à partir d'un système réel

CREATE TABLE PROPERTY
(ID                          NUMBER(9)           NOT NULL);

CREATE TABLE PROPERTY_TYPE
(ID                          NUMBER(9)           NOT NULL);

CREATE TABLE PROPERTY_LOCALE 
PROPERTY_ID                  NUMBER(9)           NOT NULL,
(LOCALE_ID                   NUMBER(9)           NOT NULL,  --language 
VALUE                        VARCHAR2(200)       NOT NULL);

CREATE TABLE PROPERTY_DEPENDENCY
(PROPERTY_ID                 NUMBER(9)           NOT NULL,
 PARENT_PROPERTY_ID          NUMBER(9)                   ,
 PROPERTY_TYPE_ID            NUMBER(9)           NOT NULL);

Ces tables établissent une liste liée de propriétés uniques et de propriétés enfant parent et elles sont utilisées ici

  CREATE TABLE CASE_PROPERTY
  (ID                        NUMBER(9)           NOT NULL,
  PARENT_ID                  NUMBER(9),
  CASE_ID                    NUMBER(9)           NOT NULL,
  PROPERTY_ID                NUMBER(9),
  PROPERTY_TYPE_ID           NUMBER(9)           NOT NULL);

Cela semble bien: obtenir tous les cas avec un property_id en une seule sélection

Obtenons une liste à choisir

 Select pl.value, pd.property_id
 from property_locale pl, property_dependency pd
 where pl.property_id = pd.property_id
 and pd.property_type_id = 2;  --example number

Essayez maintenant de sélectionner toutes les propriétés d'un cas s'il a des property_types de 3 et 4 et 5, ou pas ...

SELECT   cp2.case_id,
         (SELECT   pl.VALUE
            FROM   case_property cp, property_locale pl
           WHERE       cp.property_id = pl.property_id
                   AND CP.PROPERTY_TYPE_ID = 2
                   AND pl.locale_id = 2
                   AND cp.case_id = cp2.case_id)
            AS VALUE1,
         (SELECT   pl.VALUE
            FROM   case_property cp, property_locale pl
           WHERE       cp.property_id = pl.property_id
                   AND CP.PROPERTY_TYPE_ID = 34
                   AND pl.locale_id = 2
                   AND cp.case_id = cp2.case_id)
            AS VALUE2,
         (SELECT   pl.VALUE
            FROM   case_property cp, property_locale pl
           WHERE       cp.property_id = pl.property_id
                   AND CP.PROPERTY_TYPE_ID = 4
                   AND pl.locale_id = 2
                   AND cp.case_id = cp2.case_id)
            AS VALUE3
  FROM   case_property cp2
 WHERE   cp2.case_id = 10293  

Cela fait juste mal ... même lorsque vous utilisez des moyens plus élégants de gérer cela. Cependant, ajoutez un peu de normalisation en décomposant les propriétés pour lesquelles un cas n'aura qu'un seul property_id et cela pourrait être bien mieux.

Pour savoir quand vous avez trop de tables ou pas assez, essayez d'interroger la base de données avec des questions sur l'application, un rapport et une analyse d'année en année utiliseront.

5
kevinsky