web-dev-qa-db-fra.com

Implémentation d'un sous-type d'un sous-type dans un modèle de conception de type / sous-type avec des sous-classes mutuellement exclusives

Introduction

Pour que cette question soit utile aux futurs lecteurs, j'utiliserai le modèle de données générique pour illustrer le problème auquel je suis confronté.

Notre modèle de données se compose de 3 entités, qui seront appelées A, B et C. Afin de simplifier les choses, tous leurs attributs seront de type int.

L'entité A possède les attributs suivants: D, E et X;

L'entité B possède les attributs suivants: D, E et Y;

L'entité C a les attributs suivants: D et Z;

Puisque toutes les entités partagent l'attribut commun D, j'ai décidé d'appliquer type/sous-type design.

Important: les entités s'excluent mutuellement! Cela signifie que l'entité est soit A, soit B ou C.

Problème:

Les entités A et B ont encore un autre attribut commun E, mais cet attribut n'est pas présent dans l'entité C.

Question:

Je voudrais utiliser la caractéristique décrite ci-dessus pour optimiser davantage ma conception, si possible.

Pour être honnête, je n'ai aucune idée de comment faire cela, ni par où commencer à essayer, d'où ce post.

20

Dans la mesure où cette Question est une continuation de Mon implémentation du modèle de conception de type/sous-type (pour les sous-classes mutuellement exclusives) est-elle correcte? , qui est elle-même une continuation de Je ne sais pas comment transformer entité variable dans la table relationnelle , je demanderais: quoi exactement essayez-vous d'optimiser? Espace de rangement? Le modèle objet? Complexité des requêtes? Performances des requêtes? Il existe des compromis lors de l'optimisation d'un aspect par rapport à un autre, car vous ne pouvez pas optimiser tous les aspects en même temps.

Je suis entièrement d'accord avec les points de Remus concernant:

  • Il y a des avantages et des inconvénients à chaque approche (c.-à-d. Le facteur omniprésent "ça dépend"), et
  • La première priorité est l'efficacité du modèle de données (un modèle de données inefficace ne peut pas être corrigé par un code d'application propre et/ou efficace)

Cela dit, le choix auquel vous êtes confronté se situe entre les éléments suivants, classés par ordre de normalisation le plus faible à la plupart de normalisation:

  • promotion de la propriété E vers la table de type de base
  • le garder dans plusieurs tables de sous-types
  • normaliser complètement E vers une nouvelle table de sous-classe intermédiaire au même niveau que C, que A et B seront directement des sous-classes de ( @ réponse de MDCCL )

Examinons chaque option:

Déplacer la propriété E vers la table de type de base

PROs

  • Réduit la complexité des requêtes pour les requêtes qui nécessitent E mais pas X, Y ou Z.
  • Potentiellement plus efficace pour les requêtes nécessitant E mais pas X, Y ou Z (en particulier les requêtes agrégées) en raison de l'absence de JOIN.
  • Possibilité de créer un index sur (D, E) (et si oui, potentiellement un index filtré sur (D, E) où EntityType <> C, si une telle condition est autorisée)

CONs

  • Impossible de marquer E comme NOT NULL
  • Besoin supplémentaire CHECK CONSTRAINT sur la table de type de base pour garantir que E IS NULL lorsque EntityType = C (bien que ce ne soit pas un gros problème)
  • Besoin d'éduquer les utilisateurs du modèle de données pour savoir pourquoi E doit être NULL, et doit même être ignoré complètement, lorsque EntityType = C.
  • Un peu moins efficace lorsque E est un type de longueur fixe, et une grande partie des lignes sont pour EntityType de C (c'est-à-dire sans utiliser E donc c'est NULL), et n'utilisant pas l'option SPARSE dans la colonne ou la compression de données sur l'index clusterisé
  • Potentiellement moins efficace pour les requêtes qui n'ont pas besoin de E car la présence de E dans la table de type de base augmentera la taille de chaque ligne, ce qui à son tour diminuera le nombre de lignes pouvant tenir une page de données. Mais cela dépend fortement du type de données exact de E, du FILLFACTOR, du nombre de lignes dans la table de type de base, etc.

Conserver la propriété E dans chaque sous-type Table

PROs

  • Modèle de données plus propre (c.-à-d. Ne pas avoir à vous soucier de renseigner les autres sur la raison pour laquelle la colonne E dans la table de type de base ne doit pas être utilisée car "elle n'est vraiment pas là")
  • Ressemble probablement plus étroitement au modèle objet
  • Peut marquer la colonne comme NOT NULL s'il s'agit d'une propriété obligatoire de l'entité
  • Pas besoin d'extra CHECK CONSTRAINT sur la table de type de base pour garantir que E IS NULL lorsque EntityType = C (bien que ce ne soit pas un gain énorme)

CONs

  • Requiert JOIN pour sous-type Table (s) pour obtenir cette propriété
  • Potentiellement légèrement moins efficace lorsque vous avez besoin de E, en raison du JOIN, selon le nombre de lignes de A + B que vous avez par opposition au nombre de lignes de C il y a.
  • Un peu plus difficile/complexe pour les opérations qui traitent uniquement avec les entités A et B (et pasC) comme étant du même type " ". Bien sûr, vous pouvez résumer cela via une vue qui fait un UNION ALL entre un SELECT des tables JOINed pour A et un autre SELECT des tables JOINed pour B. Cela réduira la complexité des requêtes SELECT mais n'est pas très utile pour les requêtes INSERT et UPDATE.
  • Selon les requêtes spécifiques et la fréquence à laquelle elles sont exécutées, cela pourrait être une inefficacité potentielle dans les cas où avoir un index sur (D, E) aiderait vraiment une ou plusieurs requêtes fréquemment utilisées, car elles ne peuvent pas être indexées ensemble.

Normaliser E vers la table intermédiaire entre la classe de base et A & B

(Veuillez noter que j'aime @ la réponse de MDCCL comme une alternative viable, selon les circonstances. Ce qui suit n'est pas censé critiquer strictement cette approche, mais comme un moyen d'ajouter une certaine perspective - la mienne , bien sûr - en l'évaluant dans le même contexte que les deux options que j'avais déjà proposées. Cela permettra de clarifier plus facilement ce que je considère comme la différence relative entre la normalisation complète et l'approche actuelle de normalisation partielle.)

PROs

  • le modèle de données est entièrement normalisé (il ne peut y avoir rien de mal en soi, étant donné que c'est ce que les SGBDR sont conçus pour faire)
  • complexité des requêtes réduite pour les requêtes nécessitant A et B, mais pas C (c'est-à-dire pas besoin de deux requêtes jointes via UNION ALL)

CONs

  • un peu plus d'espace occupé (la table Bar duplique l'ID, et il y a une nouvelle colonne, BarTypeCode) [négligeable, mais quelque chose à savoir]
  • légère augmentation de la complexité des requêtes car un JOIN supplémentaire est nécessaire pour accéder à A ou B
  • augmentation de la surface de verrouillage, principalement sur INSERT (DELETE peut être gérée implicitement en marquant les clés étrangères comme ON CASCADE DELETE) puisque la transaction sera maintenue ouverte un peu plus longtemps sur la table de la classe de base (c'est-à-dire Foo) [négligeable, mais quelque chose à savoir]
  • aucune connaissance directe du type réel - A ou B - dans la table de classe de base, Foo; il ne connaît que le type Br qui peut être A ou B:

    Autrement dit, si vous devez effectuer des requêtes sur les informations de base générales mais que vous devez soit les classer par type d'entité, soit filtrer un ou plusieurs types d'entités, la table de la classe de base n'a pas suffisamment d'informations, auquel cas vous devez LEFT JOIN la table Bar. Cela réduira également l'efficacité de l'indexation de la colonne FooTypeCode.

  • aucune approche cohérente pour interagir avec A & B vs C:

    Autrement dit, si chaque entité se rapporte directement à la table de classe de base de sorte qu'il n'y a qu'un seul JOIN pour obtenir l'entité complète, alors tout le monde peut acquérir plus rapidement et facilement une familiarité en termes de travail avec le modèle de données. Il y aura une approche commune des requêtes/procédures stockées qui les rend plus rapides à développer et moins susceptibles d'avoir des bogues. Une approche cohérente permet également d'ajouter plus rapidement et plus facilement de nouveaux sous-types à l'avenir.

  • potentiellement moins adaptable aux règles métier qui évoluent avec le temps:

    Cela signifie que les choses changent toujours et il est assez facile de déplacer E vers la table de classe de base si elle devient commune à tous les sous-types. Il est également assez facile de déplacer une propriété commune vers les sous-types si des changements dans la nature des entités en font un changement valable. Il est assez facile de diviser un sous-type en deux sous-types (il suffit de créer une autre valeur SubTypeID) ou de combiner deux ou plusieurs sous-types en un seul. À l'inverse, que se passerait-il si E devenait plus tard une propriété commune à tous les sous-types? La couche intermédiaire de la table Bar n'aurait alors plus de sens et la complexité supplémentaire n'en valait pas la peine. Bien sûr, il est impossible de savoir si un tel changement se produirait dans 5 ou même 10 ans, donc la table Bar n'est pas nécessairement, ni même hautement probable, une mauvaise idée (c'est pourquoi j'ai dit " potentiellement moins adaptable"). Ce ne sont que des points à considérer; c'est un pari dans les deux sens.

  • regroupement potentiellement inapproprié:

    Ce qui signifie que le fait que la propriété E soit partagée entre les types d'entité A et B ne signifie pas que A et Bdevrait être regroupés. Ce n'est pas parce que les choses "se ressemblent" (c'est-à-dire les mêmes propriétés) qu'elles ne sont pas les mêmes.

Sommaire

Tout comme pour décider si/quand dénormaliser, la meilleure façon d'aborder cette situation particulière dépend de considérer les aspects suivants de l'utilisation du modèle de données et de s'assurer que les avantages l'emportent sur les coûts:

  • combien de lignes vous aurez pour chaque EntityType (regardez au moins 5 ans plus tard, en supposant une croissance supérieure à la moyenne)
  • combien de Go chacune de ces tables (type de base et sous-types) sera-t-elle dans 5 ans?
  • quel type de données spécifique est la propriété E
  • est-ce une seule propriété ou y a-t-il quelques, voire plusieurs, propriétés
  • quelles requêtes dont vous aurez besoin qui nécessitent E et à quelle fréquence elles seront exécutées
  • quelles requêtes dont vous aurez besoin qui n'ont pas besoin de E et à quelle fréquence elles seront exécutées

Je pense que j'ai tendance à conserver par défaut E dans les tables de sous-types séparées car c'est, à tout le moins, "plus propre". J'envisagerais de déplacer E vers la table de type de base IF: la plupart des lignes étaient pas pour EntityType de C; et le nombre de lignes était au moins dans les millions; et J'ai exécuté le plus souvent des requêtes qui nécessitaient E et/ou les requêtes qui bénéficieraient d'un index sur (D, E) soit s'exécute très fréquemment et/ou nécessite suffisamment de ressources système, de sorte que l'index réduit l'utilisation globale des ressources, ou au moins empêche les pics de consommation de ressources qui dépassent les niveaux acceptables ou qui durent assez longtemps pour provoquer un blocage excessif et/ou une augmentation des blocages .


[~ # ~] mise à jour [~ # ~]

O.P. a commenté cette réponse que:

Mes employeurs ont changé la logique commerciale, supprimant complètement E!

Ce changement est particulièrement important car c'est exactement ce que je prédis qui pourrait se produire dans la sous-section "CONs" de la table "Normalize E out to intermediary entre la classe de base et A & B "ci-dessus (6ème puce). Le problème spécifique est à quel point il est facile/difficile de refactoriser le modèle de données lorsque de tels changements se produisent (et ils le font toujours). Certains diront que tout modèle de données peut être refactorisé/modifié, alors commencez par l'idéal. Mais s'il est vrai au niveau technique que tout peut être refactorisé, la réalité de la situation est une question d'échelle.

Les ressources ne sont pas infinies, pas seulement CPU/Disque/RAM, mais aussi les ressources de développement: temps et argent. Les entreprises fixent constamment des priorités sur les projets car ces ressources sont très limitées. Et assez souvent (du moins d'après mon expérience), les projets visant à gagner en efficacité (même à la fois les performances du système ainsi que le développement plus rapide/moins de bugs) sont prioritaires en dessous des projets qui augmentent les fonctionnalités. Bien que cela soit frustrant pour nous, les techniciens, car nous comprenons les avantages à long terme des projets de refactoring, c'est juste la nature de l'entreprise que les gens d'affaires moins techniques ont plus de facilité à voir la relation directe entre les nouvelles fonctionnalités et les nouvelles. revenu. Ce que cela se résume à: "nous reviendrons pour résoudre ce problème plus tard" == "ce problème sera probablement là pour les 5 à 10 prochaines années parce que nous aurons presque toujours des choses plus importantes à travailler (ironiquement, comme les cas de support qui continuent à arriver parce que nous ne l'avons pas encore corrigé) ".

Dans cet esprit, si la taille des données est suffisamment petite pour que des modifications puissent être apportées très requête, et/ou vous avez une fenêtre de maintenance qui est assez longue pour non seulement apporter les modifications mais aussi pour annuler si quelque chose se passe incorrect, puis normaliser E vers une table intermédiaire entre la table de classe de base et les tables de sous-classe A & B pourrait fonctionner (bien que cela ne vous laisse toujours pas de connaissance directe du type spécifique (A ou B) dans la table de la classe de base). MAIS, si vous avez des centaines de millions de lignes dans ces tables et une quantité incroyable de code référençant les tables (code qui doit être testé lorsque des modifications sont apportées), alors il est généralement avantageux d'être plus pragmatique qu'idéaliste. Et c'est l'environnement auquel j'ai dû faire face pendant des années: 987 millions de lignes et 615 Go dans la table de classe de base, répartis sur 18 serveurs. Et tellement de code a frappé ces tables (tables de classe de base et de sous-classe) qu'il y avait beaucoup de résistance - principalement de la direction mais parfois du reste de l'équipe - à apporter des changements en raison de la quantité de développement et Ressources d'AQ qui devraient être allouées.

Donc, encore une fois, la "meilleure" approche ne peut être déterminée que situation par situation: vous devez connaître votre système (c'est-à-dire la quantité de données et la façon dont les tables et le code sont tous liés), comment effectuer la refactorisation et les personnes avec qui vous travaillez (votre équipe et éventuellement la direction - pouvez-vous obtenir leur adhésion pour un tel projet?). Il y a quelques changements que je mentionnais et planifiais depuis 1 à 2 ans, et j'ai pris plusieurs sprints/versions pour obtenir peut-être 85% d'entre eux implémentés. Mais si vous n'avez que <1 million de lignes et pas beaucoup de code lié à ces tables, vous pouvez probablement commencer du côté le plus idéal/"pur" des choses.

N'oubliez pas, quelle que soit la voie que vous choisissez, faites attention au moins au fonctionnement de ce modèle au cours des 2 prochaines années (si possible). Faites attention à ce qui a fonctionné et à ce qui a causé la douleur, même si cela semblait être la plus grande idée de l'époque (ce qui signifie que vous devez également vous permettre d'accepter de foirer - nous le faisons tous - afin que vous puissiez honnêtement évaluer les points douloureux. ). Et faites attention à pourquoi certaines décisions ont fonctionné ou non afin que vous puissiez prendre des décisions qui sont plus probablement pour être "meilleures" la prochaine fois :-) .

6
Solomon Rutzky

Selon Martin Fowler, il existe 3 approches au problème de l'héritage de table:

  • Héritage de table unique : Une table représente tous les types. Les attributs inutilisés sont NULL.
  • Concrete Table Inheritance : Une table par type de béton, chaque colonne de table pour chaque attribut du type. Aucune relation entre les tables.
  • Class Table Inheritance : Une table par type, chaque table n'a d'attributs que pour les nouveaux attributs non hérités. Les tables sont liées, reflétant la hiérarchie d'héritage de type réelle.

Vous pouvez commencer par ceux-ci comme point de départ pour rechercher les avantages et les inconvénients de chaque approche. L'essentiel est que toutes les approches ont des inconvénients majeurs, et aucune a un avantage écrasant. Mieux connu sous le nom de non-correspondance de l'impédance relationnelle des objets , ce problème n'a pas encore trouvé de solution.

Personnellement, je trouve que le type de problèmes qu'une mauvaise conception relationnelle peut entraîner sont des ordres de grandeur plus graves que le type de problèmes résultant d'une mauvaise type conception. Une mauvaise conception de la base de données entraîne des requêtes lentes, des anomalies de mise à jour, une explosion de la taille des données, des blocages et des applications qui ne répondent pas, et des dizaines à des centaines de gigaoctets de données coulées dans le mauvais format . Une mauvaise conception de type conduit à maintenir et à mettre à jour le code , pas le runtime. Par conséquent, dans mon livre, la conception relationnelle correcte l'emporte sur la pureté du type OO) encore et encore et encore.

18
Remus Rusanu

Selon mon interprétation de vos spécifications, vous voulez trouver une méthode pour implémenter deux (mais connectés) supertype-subtype structures.

Afin d'exposer une approche pour réaliser la tâche susmentionnée, je vais ajouter au scénario en cause les deux types d'entités classiques hypothétique appelés Foo et Bar, que je détaillerai ci-dessous.

Règles métier

Voici quelques déclarations qui m'aideront à créer un modèle logique:

  • A Foo is either one Bar or one C
  • A Foo is categorized by one FooType
  • A Bar is either one A or one C
  • A Bar is classified by one BarType

Modèle logique

Et puis, l'IDEF1X résultant [1]  le modèle logique est montré dans Figure 1 (et vous pouvez le télécharger depuis Dropbox au format PDF , aussi):

Figure 1 - Hypothetical Supertype-Subtype Relationships Data Model

L'ajout de Foo et Bar

Je n'ai pas ajouté Foo et Bar pour améliorer l'apparence du modèle, mais pour le rendre plus expressif. Je considère qu'ils sont importants pour les raisons suivantes:

  • Comme A et B partagent l'attribut nommé E, cette fonctionnalité suggère qu'il s'agit de types de sous-entité d'une sorte distincte (mais liée) de - concept, événement, personne, mesure, etc., que j'ai représenté au moyen du Bar type de superentité qui, à son tour, est un type de sous-entité de Foo, qui contient l'attribut D en haut de la hiérarchie.

  • Puisque C ne partage qu'un attribut avec le reste des types d'entités en discussion, c'est-à-dire D, cet aspect insinue qu'il s'agit d'un type de sous-entité d'un autre type de concept, événement, personne, mesure, etc., j'ai donc décrit cette circonstance en vertu du Foo type super entité.

Cependant, ce ne sont que des hypothèses, et comme une base de données relationnelle est censée refléter avec précision la sémantique d'un certain contexte commercial, vous devez identifier et classer tous les choses intéressantes dans votre domaine spécifique afin que vous puissiez, précisément, capturer plus de sens.

Facteurs importants lors de la phase de conception

Il est très utile d'être conscient du fait que, en mettant toute la terminologie de côté, un cluster exclusif de supertype-sous-type est une relation ordinaire. Décrivons la situation de la manière suivante:

  • Chaque type de superentité exclusif est lié à un seul complément type de sous-entité.

Ainsi, il y a une correspondance (ou cardinalité) de un à un (1: 1) dans ces cas.

Comme vous le savez d'après vos articles précédents, l'attribut discriminator (colonne, lorsqu'il est implémenté) joue un rôle primordial lors de la création d'une association de cette nature, car il indique l'instance de sous-type correcte avec lequel le supertype est connecté. La migration de la CLÉ PRIMAIRE de (i) le supertype à (ii) les sous-types est également de première importance.

Structure DDL en béton

Et puis j'ai écrit une structure DDL basée sur le modèle logique présenté ci-dessus:

CREATE TABLE FooType -- Look-up table.
(
    FooTypeCode     CHAR(2)  NOT NULL,
    Description     CHAR(90) NOT NULL, 
    CreatedDateTime DATETIME NOT NULL,
    CONSTRAINT PK_FooType             PRIMARY KEY (FooTypeCode),
    CONSTRAINT AK_FooType_Description UNIQUE      (Description)
);

CREATE TABLE Foo -- Supertype
(
    FooId           INT      NOT NULL, -- This PK migrates (1) to ‘Bar’ as ‘BarId’, (2) to ‘A’ as ‘AId’, (3) to ‘B’ as ‘BId’, and (4) to ‘C’ as ‘CId’.
    FooTypeCode     CHAR(2)  NOT NULL, -- Discriminator column.
    D               INT      NOT NULL, -- Column that applies to ‘Bar’ (and therefore to ‘A’ and ‘B’) and ‘C’.
    CreatedDateTime DATETIME NOT NULL,
    CONSTRAINT PK_Foo                 PRIMARY KEY (FooId),
    CONSTRAINT FK_from_Foo_to_FooType FOREIGN KEY (FooTypeCode)
        REFERENCES FooType (FooTypeCode)
);

CREATE TABLE BarType -- Look-up table.
(
    BarTypeCode CHAR(1)  NOT NULL,  
    Description CHAR(90) NOT NULL,  
    CONSTRAINT PK_BarType             PRIMARY KEY (BarTypeCode),
    CONSTRAINT AK_BarType_Description UNIQUE      (Description)
);

CREATE TABLE Bar -- Subtype of ‘Foo’.
(
    BarId       INT     NOT NULL, -- PK and FK.
    BarTypeCode CHAR(1) NOT NULL, -- Discriminator column. 
    E           INT     NOT NULL, -- Column that applies to ‘A’ and ‘B’.
    CONSTRAINT PK_Bar             PRIMARY KEY (BarId),
    CONSTRAINT FK_from_Bar_to_Foo FOREIGN KEY (BarId)
        REFERENCES Foo (FooId),
    CONSTRAINT FK_from_Bar_to_BarType FOREIGN KEY (BarTypeCode)
        REFERENCES BarType (BarTypeCode)    
);

CREATE TABLE A -- Subtype of ‘Bar’.
(
    AId INT NOT NULL, -- PK and FK.
    X   INT NOT NULL, -- Particular column.  
    CONSTRAINT PK_A             PRIMARY KEY (AId),
    CONSTRAINT FK_from_A_to_Bar FOREIGN KEY (AId)
        REFERENCES Bar (BarId)  
);

CREATE TABLE B -- (1) Subtype of ‘Bar’ and (2) supertype of ‘A’ and ‘B’.
(
    BId INT NOT NULL, -- PK and FK.
    Y   INT NOT NULL, -- Particular column.  
    CONSTRAINT PK_B             PRIMARY KEY (BId),
    CONSTRAINT FK_from_B_to_Bar FOREIGN KEY (BId)
        REFERENCES Bar (BarId)  
);

CREATE TABLE C -- Subtype of ‘Foo’.
(
    CId INT NOT NULL, -- PK and FK.
    Z   INT NOT NULL, -- Particular column.  
    CONSTRAINT PK_C             PRIMARY KEY (CId),
    CONSTRAINT FK_from_C_to_Foo FOREIGN KEY (FooId)
        REFERENCES Foo (FooId)  
);

Avec cette structure, vous évitez le stockage de marques NULL dans vos tables de base (ou relations ), ce qui introduirait une ambiguïté dans votre base de données.

Intégrité, cohérence et autres considérations

Une fois que vous implémentez votre base de données, vous devez vous assurer que (a) chaque sous-type exclusif est toujours complétée par son homologue sous-type correspondante et, à son tour, garantir que (b) une telle ligne sous-type est compatible avec la valeur contenue dans la colonne supertype discriminator. Par conséquent, il est très pratique d'utiliser ACID TRANSACTIONS afin de vous assurer que ces conditions sont remplies dans votre base de données.

Vous ne devez pas abandonner la solidité logique, l'auto-expressivité et la précision de votre base de données, ce sont des aspects qui rendent définitivement votre base de données plus solide.

Les deux réponses précédemment publiées contiennent déjà des points pertinents qui méritent certainement d'être pris en compte lors de la conception, de la création et de la gestion de votre base de données et de ses programmes d'application.

Récupération de données via des définitions VIEW

Vous pouvez configurer des vues qui combinent ​​colonnes des différents sous-types de supertype groupes, afin que vous puissiez récupérer les données à portée de main sans, par exemple, écrire les clauses JOIN nécessaires chaque temps. De cette façon, vous pouvez sélectionner directement à partir de la vue (une relation dérivée ou table ) d'intérêt avec facilité.

Comme vous pouvez le voir, "Ted" Codd était, sans aucun doute, un génie. Les outils qu'il a légués sont assez solides et élégants et, bien sûr, bien intégrés les uns aux autres.

Ressources associées

Si vous souhaitez analyser une base de données étendue qui implique des relations supertype-sous-type, vous trouverez de valeur les réponses extraordinaires proposées par @ PerformanceDBA aux questions de débordement de pile suivantes:


Remarque

1. Définition d'intégration pour la modélisation de l'information ( IDEF1X ) est une technique de modélisation de données hautement recommandable qui a été établie en tant que norme en décembre 1993 par le National Institute of Standards and Technology des États-Unis ( [~ # ~] nist [~ # ~] ). Il est solidement basé sur (a) les premiers documents théoriques rédigés par le Dr E. F. Codd; sur (b) la vue Entity-Relationship des données, développée par Dr PP Chen ; et aussi sur (c) la technique de conception de base de données logique, créée par Robert G. Brown. Il convient de noter que IDEF1X a été formalisé au moyen d'une logique de premier ordre.

6
MDCCL