2010-11-29 28 views
3

J'essaie de décider d'une base de données. Plus précisément, il s'agit d'une sous-partie d'une conception plus large. Fondamentalement, il existe des "Emplacements" - chaque emplacement peut avoir un nombre quelconque de capteurs associés, et il peut avoir un enregistreur (mais seulement 1).Base de données "supertable" vs plusieurs tables vs tableau générique

J'ai des lectures de capteur et j'ai des lectures d'enregistreur, chacune assez différente pour justifier des tables séparées.

Si une lecture de capteur est hors de portée, une alerte est générée. Tant que la lecture d'un capteur reste hors de portée, il reste associé à cette alerte. Vous obtenez ainsi une alerte contenant de nombreuses lectures me permettant de tracer l'alerte plus tard pour repérer les tendances, etc.

Même avec les lectures de l'enregistreur.

Voici mes 3 idées à ce jour pour stocker ces données:

Option 1:

 
Location [Table] 
- Id [PK] 
- Name 
- HasLogger 

LiveSensor [Table] 
- LocationId [FK] 
- Id [PK] 

LiveSensorReading [Table] 
- Id [PK] 
- SensorId [FK] 
- Value 

LiveSensorAlert [Table] 
- Id [PK] 
- SensorReadingId [FK] (may not be needed - enforces need to always have at least 1 reading) 

LiveSensorAlertCorrectiveAction [Table] 
- LiveSensorAlertId [FK] 
- CorrectiveActionId [FK] 
- ByUserId [FK] 

LiveSensorAlertAcknowledgement [Table] 
- LiveSensorAlertId [FK] 
- ByUserID [FK] 

LiveSensorAlertReading [Table] 
- SensorAlertId [FK] 
- SensorReadingId [FK] 

LoggerReading [Table] 
- LocationId [FK] 
- Value 

LoggerAlert [Table] 
- Id [PK] 
- LoggerReadingId [FK] (may not be needed - enforces need to always have at least 1 reading) 

LoggerAlertReading [Table] 
- LoggerAlertId [FK] 
- LoggerReadingId [FK] 

LoggerAlertCorrectiveAction [Table] 
- LoggerAlertId [FK] 
- CorrectiveActionId [FK] 
- ByUserId [FK] 

LoggerAlertAcknowledgement [Table] 
- LoggerAlertId [FK] 
- ByUserID [FK] 
  • Problème: Beaucoup de tables répétées (est-ce que vraiment d'importance si ??)

Option 2:

 
Location [Table] 
- Id 
- Name 
- HasLogger 

Sensor [Table] 
- Id [PK] 
- LocationId [FK] 

SensorReading [Table] 
- Id [PK] 
- SensorId [FK] 
- Value 

LoggerReading 
- LocationId [FK] 
- Value 

Alert [Table] 
- Id [PK] 

AlertCorrectiveAction [Table] 
- AlertId [FK] 
- CorrectiveActionId [FK] 
- ByUserId [FK] 

AlertAcknowledgement [Table] 
- AlertId [FK] 
- ByUserId [FK] 

SensorAlertReading 
- AlertId [FK] 
- SensorReadingId [FK] 

LoggerAlertReading 
- AlertId [FK] 
- LoggerReadingId [FK] 
  • Problème: n'applique pas la règle "au moins 1 lecture par alerte".
  • Problème: Permet à plus d'un type de lecture de référencer la même alerte.

Option 3:

 
Location [Table] 
- Id 
- Name 
- HasLogger 

Sensor [Table] 
- Id [PK] 
- LocationId [FK] 

SensorReading [Table] 
- Id [PK] 
- SensorId [FK] 
- Value 

LoggerReading 
- LocationId [FK] 
- Value 

Alert [Table] "super table" 
- Id [PK] 

LoggerAlert [Table] 
- AlertId [PK, FK] 
- LoggerReadingId [FK] 

SensorAlert [Table] 
- AlertId [PK, FK] 
- SensorReadingId [FK] 

AlertCorrectiveAction [Table] 
- AlertId [FK] 
- CorrectiveActionId [FK] 
- ByUserId [FK] 

AlertAcknowledgement [Table] 
- AlertId [FK] 
- ByUserId [FK] 

SensorAlertReading [Table] 
- SensorAlertId [FK] 
- SensorReadingId [FK] 

LoggerAlertReading [Table] 
- LoggerAlertId [FK] 
- LoggerReadingId [FK] 
  • Problème: Rien arrêter un LoggerAlert et SensorAlert référencement même alerte (même problème que l'option 2).
  • Problème: obscurcit base de données

Je pense que jusqu'à présent, je suis préférant (n'est pas table maîtresse plus d'un concept OO Une base de données est censée être purement relationnelle est-ce pas?) option 1 parce que cela semble si propre et que l'intention est claire (j'espère!), même si je répète les tables efficacement.

Le seul petit problème auquel je viens de penser est que des lectures pour différents capteurs pourraient encore être associées à une seule alarme. Je me demande ce que les gens pensent des options ci-dessus. J'ai vu l'utilisation de "super tables" souvent silencieuse, mais pour une raison quelconque, je ne me sens pas bien - cela ressemble presque à un hack, surtout quand je vois les méthodes pour essayer d'assurer l'intégrité des données. Il semble plus proche de la programmation OO que de la conception relationnelle.

Merci.

EDIT: Certains plus d'informations pour aider à répondre à certaines des questions ci-dessous:

La plupart du temps la base de données est uniquement manipulé par un serveur d'application, si cela fait une différence. Les alertes en direct et les alertes des enregistreurs sont généralement traitées de la même manière. Je traiterai donc probablement toutes les alertes la plupart du temps, plutôt que de traiter les alertes de consignation et les alertes en direct de différentes manières.

L'enregistreur a des colonnes assez spécifiques qui résident dans la table de localisation. Étant donné que l'emplacement et l'enregistreur seraient un mappage de 1 à 1, j'ai décidé de ne pas avoir de table de journalisation séparée et, jusqu'à présent, il semble que cela ait bien fonctionné et que cela reste simple. Exemples de colonnes: LoggerRFID (int), LoggerUpperLimit (float), LoggerLowerLimit (float), etc. Vous pourriez presque faire valoir qu'un enregistreur est un capteur, mais je suis allé dans cette direction et cela ne s'est pas très bien passé. Je peux presque accepter de rendre les alertes génériques, mais comme l'une des réponses dit que j'essaie d'en être très sûr, je poursuis la recherche le plus longtemps possible avant de choisir un chemin spécifique.

+4

Si je devais travailler sur ces tables, je préférerais que vous n'ayez pas de colonnes nommées simplement "Id". Pour moi, il est plus facile que la colonne FK et la colonne PK aient le même nom. Il suffit d'étendre le nom "Id" à "SensorReadingId" dans le tableau "SensorReading" comme vous le faites dans le tableau "SensorAlert". Cela aide quand vous avez besoin de chercher beaucoup de code (vous obtenez un million de faux résultats sur "Id" mais très peu sur "SensorReadingId") ou avoir de grandes requêtes avec beaucoup de tables, chacune avec une colonne "Id". –

+0

Point pris - c'est comme ça que je l'ai toujours fait, mais je vais certainement penser à changer de comportement car l'argument semble valable. – Mark

Répondre

1

Quelques réflexions (idées et opinions, non réponses) sur ce modèle:

Le « supertable » (type/sous-type) est convaincant, mais il peut être difficile à mettre en œuvre et de soutien. Quelques astuces:

ALERT 
    AlertId PK 1/2 
    AlertType PK 2/2 Check constraint (1 or 2, or better L or S) 

... qui est une clé primaire composée, où "type" doit toujours être L) og ou S) Ensor.

LOGALERT 
    LogAlertId PK 1/2 FK 1/2 
    AlertType PK 2/2 FK 2/2 

(and again for SENSORALERT) 

... qui est, même clé primaire composé, et la clé étrangère est sur les deux colonnes. Fait de cette façon, il ne peut y avoir qu'une table de sous-type pour une table de type donnée, et la table supérieure montre clairement quel sous-type est impliqué. Aucun moyen d'imposer l'existence d'une ligne dans la table de sous-type, alors configurez vos données avec soin. Et une grande partie de la complexité de l'interrogation peut être traitée (couverte) à l'aide de vues. L'inconvénient est, il est complexe, déroutant pour ceux qui ne sont pas (encore) familiers avec elle, et nécessitera un soutien et des efforts supplémentaires. La vraie question est, est-ce que ça vaut le coup?

  • À quelle fréquence devez-vous faire face à toutes les alertes, non seulement journaux ou seulement du capteur? Si la plupart du temps, vous n'avez à traiter qu'avec l'un ou l'autre, cela n'en vaut probablement pas la peine.
  • De combien de détails spécifiques au Log ou au Capteur avez-vous affaire? Au-delà des événements réels liés à une alerte individuelle, dans quelle mesure les deux attributs sont-ils similaires (détails dans les colonnes)? Si les utilisateurs, les remerciements et les actions correctives sont (suffisamment) identiques, vous pouvez en faire des attributs (colonnes) d'ALERT, mais sinon vous devez les atttribuer du sous-type approprié, et vous perdez l'avantage de consolidation du supertype.
  • Et vous devez le corriger maintenant, pendant la conception. Faites des recherches, posez des questions, regardez des boules de cristal (par exemple, réfléchissez à ce qui pourrait arriver dans le futur pour invalider les suppositions actuelles), car si vous vous trompez, vous et vos successeurs devrez peut-être vivre avec lui pour toujours.
+0

J'ai déjà vu cette idée, c'est une astuce, mais ça ne tient pas la route pour quelque raison que ce soit, c'est comme un hack. Peut-être que j'ai juste besoin de m'habituer à l'idée! Je vais essayer de répondre à vos 3 questions en éditant ma question initiale. – Mark

+0

Je ne peux pas faire des accusés de réception ou des actions correctives des attributs d'alerte pour 2 raisons. Je devrais d'abord faire des colonnes NULL-capable. Deuxièmement, il s'agit d'une base de données historique, donc je dois être en mesure de voir l'état de la base de données à un moment donné (chaque ligne de chaque table a une colonne "timestamp"). – Mark

+0

Pour répondre à votre dernier point: Oui, d'où la question ici et je suis également à la recherche d'articles. Le problème est qu'il semble très subjectif, ce qui signifie que la décision est moins sur les faits et plus sur ce que je ressens à ce sujet - que je n'aime pas ;-) – Mark

1

Vous pouvez ajouter une colonne ObjectType à vos tables en miroir dans l'option un et fournir des valeurs de Sensor ou Logger. Votre conception de base de données alors ressembler à quelque chose comme ceci:

Location [Table] 
- Id 
- Name 
- HasLogger 

ObjectType [Table] 
- Id [PK] 
- Name -- either Sensor or Logger 
- Description 

Object [Table] 
- Id [PK] 
- LocationId [FK] 
- ObjectTypeId [FK] 

Reading [Table] 
- Id [PK] 
- ObjectId [FK] 
- Value 

ObjectReading 
- ObjectId [FK] 
- ReadingId [FK] 

Alert [Table] 
- Id [PK] 
- ReadingId [FK] 

AlertCorrectiveAction [Table] 
- AlertId [FK] 
- CorrectiveActionId [FK] 
- ByUserId [FK] 

AlertAcknowledgement [Table] 
- AlertId [FK] 
- ByUserId [FK] 

Cette conception fait obscurcir l'objectif sous-jacent de la base de données un peu, en grande partie parce que je ne pouvais pas penser à un meilleur mot pour décrire « capteur ou enregistreur » que " object "- s'il existe un terme spécifique qui pourrait décrire collectivement quelque chose attaché à un emplacement, cela faciliterait certainement la compréhension de la base de données.

Vous pouvez également supprimer la colonne Id de ObjectType et rendre le nom une clé primaire si vous n'êtes pas particulièrement sensible aux ID non-entiers dans les tables. J'ai eu de mauvaises expériences avec des tables comme ObjectType où la clé primaire n'est pas un entier, donc j'en utilise presque toujours un. Je suis également d'accord avec l'évaluation de KM ci-dessus que l'ID de clé primaire de chaque table devrait être nommé quelque chose de plus long que «Id».

+0

Ceci est similaire à mon idée. Où j'ai tapé/sous-typé des alertes, @jwiscarson a lancé la hiérarchie à Log/Sensor. Je me suis concentré sur les Alertes parce qu'elles semblaient déjà similaires, et je devinais que Logs/Sensors avait beaucoup plus de détails uniques à gérer ... mais sinon, oui, tapez/sous-type à ce niveau. –

+0

Je fais comme ça, mais je pense que cela sur généralise les données et supprime également certaines contraintes, comme si un emplacement ne peut avoir qu'un enregistreur. Je suppose que cela peut être contraint dans l'application, mais il doit aussi gérer le cas quand il y en a plus d'un, peut-être parce que quelqu'un l'a manuellement ajouté à la base de données. D'un autre côté, devrais-je restreindre la base de données comme ça? Je suppose que les exigences peuvent changer un jour. Ah, prendre des décisions. – Mark

+0

Je suis d'accord sur la généralisation - c'est le cas lorsque vous vous retrouvez sans terminologie appropriée pour décrire un sous-ensemble de données, malheureusement. En ce qui concerne la relation un-à-un des enregistreurs et des emplacements: vous pouvez également contraindre dans la base de données avec une clé unique, si c'est critique. – jwiscarson

1

Je pense que cette question a été répondue dans votre other question, avec le modèle de données complet; sinon (s'il y a quelque chose en suspens), s'il vous plaît poster un Modifier à cette question.

Si vous êtes intéressé par le Supertype-Sous-type Structure relationnelle, dans un sens général, this question peut-être d'intérêt pour vous.

Puis-je vous suggérer de fermer cette question.