如何在mysql中存储类型可以是数字,日期或字符串的数据

Ste*_*son 2 mysql sql database-design entity-attribute-value

我们正在开发一个监控系统.在我们的系统中,值由不同服务器上运行的代理报告.报告的观察结果可以是如下值:

  • 数值.例如"CPU USAGE"= 55.含义55%的CPU正在使用中.
  • 某些事件被解雇了.例如"备份完成".
  • 状态:例如,SQL Server处于脱机状态.

我们希望存储这些观察结果(这些观察结果不会提前知道,并且会在不重新编译的情况下动态添加到系统中).

我们正在考虑在观察表中添加不同的列,如下所示:

IntMeasure -> INTEGER
FloatMeasure -> FLOAT
Status -> varchar(255)
Run Code Online (Sandbox Code Playgroud)

因此,如果我们要存储的值是一个数字,我们可以根据类型使用IntMeasure或FloatMeasure.如果值是状态,我们可以存储状态文字字符串(如果我们决定添加状态(id,name)表,则存储状态ID).

我们假设有可能有一个更正确的设计,但由于连接和动态表名取决于类型,可能会变得缓慢和黑暗?如果我们无法在查询中预先指定表,那么联接将如何工作?

Tom*_*att 6

我还没有做过正式的研究,但根据我自己的经验,我猜测超过80%的数据库设计缺陷都是从设计中产生的,而性能是最重要的(如果不是)考虑因素.

如果一个好的设计需要多个表,那么创建多个表.不要自动假设连接是要避免的.它们很少是性能问题的真正原因.

数据完整性的首要考虑因素,首先是数据库设计的所有阶段."答案可能并不总是正确的,但我们可以很快得到它"并不是任何商店应该努力的目标.一旦数据完整性被锁定,如果性能成为问题,就可以解决它.不要牺牲数据完整性,特别是要解决可能不存在的问题.

考虑到这一点,看看你需要什么.您有需要存储的观察结果.这些观察结果可以在属性的数量和类型上有所不同,并且可以是诸如测量值,事件通知和状态变化之类的事物,以及未来观察的可能性.

这似乎符合标准的"类型/子类型"模式,"观察"条目是类型,每种类型或种类的观察都是子类型,并建议某种形式的类型指示符字段,例如:

create table Observations(
   ...,
   ObservationKind  char( 1 ) check( ObservationKind in( 'M', 'E', 'S' )),
   ...
);
Run Code Online (Sandbox Code Playgroud)

但是在检查约束中对这样的列表进行硬编码具有非常低的可维护性级别.它成为模式的一部分,只能使用DDL语句进行更改.不是你的DBA会期待的东西.

所以在他们自己的查找表中有各种观察结果:

ID  Name         Meaning
==  ===========  =======
M   Measurement  The value of some system metric (CPU_Usage).
E   Event        An event has been detected.
S   Status       A change in a status has been detected.
Run Code Online (Sandbox Code Playgroud)

(char字段也可以是int或smallint.我在这里使用char来说明.)

然后用PK和所有观察共有的属性填写Observations表.

create table Observations(
   ID               int identity primary key,
   ObservationKind  char( 1 ) not null,
   DateEntered      date not null,
   ...,
   constraint FK_ObservationKind foreign key( ObservationKind )
      references ObservationKinds( ID ),
   constraint UQ_ObservationIDKind( ID, ObservationKind )
);
Run Code Online (Sandbox Code Playgroud)

在Kind字段和PK的组合上创建一个唯一索引可能看起来很奇怪,它本身就是唯一的,但请耐心等待一下.

现在每种类型或子类型都有自己的表.请注意,每种观察都会获得一个表,而不是数据类型.

create table Measurements(
    ID                   int not null,
    ObservationKind      char( 1 ) check( ObservationKind = 'M' ),
    Name                 varchar( 32 ) not null, -- Such as "CPU Usage"
    Value                double not null, -- such as 55.00
    ...,  -- other attributes of Measurement observations
    constraint PK_Measurements primary key( ID, ObservationKind ),
    constraint FK_Measurements_Observations foreign key( ID, ObservationKind )
        references Observations( ID, ObservationKind )
);
Run Code Online (Sandbox Code Playgroud)

对于其他类型的观察,前两个字段将是相同的,除了检查约束将强制该值为适当的类型.其他字段的数量,名称和数据类型可能不同.

让我们来看一下测量表中可能存在的示例元组:

ID    ObservationKind  Name       Value  ...
====  ===============  =========  =====
1001  M                CPU Usage  55.0   ...
Run Code Online (Sandbox Code Playgroud)

为了使此元组存在于此表中,匹配条目必须首先存在于Observations表中,ID值为1001,观察类型值为"M".在Observations表或Measurements表中不能存在ID值为1001的其他条目,并且在任何其他"种类"表(事件,状态)中根本不存在.对于所有类型的表,它的工作方式相同.

我还建议为每种观察创建一个视图,它将提供每种类型的连接与主要观察表:

create view MeasurementObservations as
    select ...
    from   Observations o
    join   Measurements m
        on m.ID = o.ID;
Run Code Online (Sandbox Code Playgroud)

任何仅适用于测量的代码都只需要点击此视图而不是基础表.使用视图在应用程序代码和原始数据之间创建抽象墙极大地增强了数据库的可维护性.

现在创建另一种观察,例如"Error",涉及到ObservationKinds表的简单Insert语句:

F   Fault        A fault or error has been detected.
Run Code Online (Sandbox Code Playgroud)

当然,您需要为这些错误观察创建一个新表和视图,但这样做对现有表,视图或应用程序代码没有影响(当然,除了编写新代码以使用新观察之外) .