在实体上存储更改:MySQL是合适的解决方案吗?
我想将所做的更改存储在“实体”表中。这应该像一个日志。目前在MySQL中使用此表实现:在实体上存储更改:MySQL是合适的解决方案吗?,mysql,database-design,entity-attribute-value,database-partitioning,temporal-database,Mysql,Database Design,Entity Attribute Value,Database Partitioning,Temporal Database,我想将所做的更改存储在“实体”表中。这应该像一个日志。目前在MySQL中使用此表实现: CREATE TABLE `entitychange` ( `id` int(11) unsigned NOT NULL AUTO_INCREMENT, `entity_id` int(10) unsigned NOT NULL, `entitytype` enum('STRING_1','STRING_2','SOMEBOOL','SOMEDOUBLE','SOMETIMESTAMP') NOT
CREATE TABLE `entitychange` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`entity_id` int(10) unsigned NOT NULL,
`entitytype` enum('STRING_1','STRING_2','SOMEBOOL','SOMEDOUBLE','SOMETIMESTAMP') NOT NULL DEFAULT 'STRING_1',
`when` TIMESTAMP NOT NULL,
`value` TEXT,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
=我的entity\u id
表的主键entity
=在entitytype
表中更改的字段。有时只更改一个字段,有时更改多个字段。一次更改=一行实体
=字段“新值”的字符串表示形式value
示例:将Field
entity.somedouble
从3更改为2时,我运行以下查询:
UPDATE entity SET somedouble = 2 WHERE entity_id = 123;
INSERT INTO entitychange (entity_id,entitytype,value) VALUES (123,'SOMEDOUBLE',2);
我需要
选择过去15天特定实体和entitytype的更改。例如:在过去15天内,实体id123
的最后一次更改为SOMEDOUBLE
现在,有两件事我不喜欢:
所有数据都存储为文本
——虽然大多数(小于1%)不是真正的文本,但在我的例子中,大多数值都是双值
。这是个大问题吗
插入时,表的速度变得非常非常慢,因为表已经有2亿行了。因此,目前我的服务器负载高达10-15
我的问题:如何解决这两个“瓶颈”?我需要缩放。
我的做法是:
按如下方式存储:(单击浏览)-将更改存储在entitychange
表中,然后根据其数据类型将值存储在entitychange[bool | timestamp | double | string]
使用散列分区(实体id)
——我想到了大约50个分区李>
我应该使用另一个数据库系统,也许是MongoDB吗
现在我想我明白你们需要什么了,一个记录历史发生变化的可版本表。这可能是实现相同目标的另一种方法,您可以轻松地进行一些快速测试,以查看它是否比当前解决方案提供更好的性能。这是Symfony PHP框架在Doctrine中使用可版本化插件的方式。
请记住,有两个键的主键唯一索引,版本和fk_实体。
还可以查看保存的值。您将在未更改的字段中保存0值,在更改的字段中保存更改的值
CREATE TABLE `entity_versionable` (
`version` INT(11) UNSIGNED NOT NULL AUTO_INCREMENT,
`fk_entity` INT(10) UNSIGNED NOT NULL,
`str1` VARCHAR(255),
`str2` VARCHAR(255),
`bool1` BOOLEAN,
`double1` DOUBLE,
`date` TIMESTAMP NOT NULL,
PRIMARY KEY (`version`,`fk_entity`)
) ENGINE=INNODB DEFAULT CHARSET=latin1;
INSERT INTO `entity_versionable` (fk_entity, str1, str2, bool1, double1, DATE)
VALUES ("1", "a1", "0", "0", "0", "2013-06-02 17:13:16");
INSERT INTO `entity_versionable` (fk_entity, str1, str2, bool1, double1, DATE)
VALUES ("1", "a2", "0", "0", "0", "2013-06-11 17:13:12");
INSERT INTO `entity_versionable` (fk_entity, str1, str2, bool1, double1, DATE)
VALUES ("1", "0", "b1", "0", "0", "2013-06-11 17:13:21");
INSERT INTO `entity_versionable` (fk_entity, str1, str2, bool1, double1, DATE)
VALUES ("1", "0", "b2", "0", "0", "2013-06-11 17:13:42");
INSERT INTO `entity_versionable` (fk_entity, str1, str2, bool1, double1, DATE)
VALUES ("1", "0", "0", "1", "0", "2013-06-16 17:19:31");
/*Another example*/
INSERT INTO `entity_versionable` (fk_entity, str1, str2, bool1, double1, DATE)
VALUES ("1", "a1", "b1", "0", "0", CURRENT_TIMESTAMP);
SELECT * FROM `entity_versionable` t WHERE
(
(t.`fk_entity`="1") AND
(t.`date` >= (CURDATE() - INTERVAL 15 DAY))
);
可能是提高性能的另一个步骤,可以是将所有历史日志记录保存在单独的表中,每月一次左右。这样,每个表中就不会有很多记录,而且按日期搜索会非常快 这里有两个主要挑战:
如何高效地存储数据,即占用更少的空间和易于使用的格式
2-3。管理一个大表:归档、易于备份和恢复
2-3。性能优化:更快的插入和选择
高效存储数据
值
字段。我建议使用VARCHAR(N)
。
原因:
- 使用N如果我面对您提到的问题,我会像下面那样设计日志表:
EntityName
:(字符串)正在操作的实体。(必填)
ObjectId
:正在操作的实体,主键
字段名
:(字符串)实体字段名
OldValue
:(字符串)实体字段旧值
NewValue
:(字符串)实体字段新值
UserCode
:应用程序用户唯一标识符。(强制性)
TransactionCode
:任何更改实体的操作都需要具有唯一的事务代码(如GUID)(必填),
如果实体的更新更改了多个字段,则这些列将是跟踪更新(transaction)中所有更改的关键点
ChangeDate
:交易日期。(强制性)
FieldType
:枚举或文本显示字段类型,如text或Double。(强制性)
使用这种方法
可以跟踪任何实体(表)
报告将是可读的
只记录更改。
事务代码将是通过单个操作检测更改的关键。
顺便说一句
不需要,在单个表中,您将有更改和数据类型
Use partitioning by HASH(entity_id)
我更喜欢按ChangeDate分区,或者为ChangeDate创建备份表,这些表足够旧,可以备份并从主日志表中删除
Should I use another database system, maybe MongoDB?
任何数据库都有其自身的优缺点,您可以在任何RDBMS上使用该设计。
MongoDB等基于文档的数据库的有用比较
希望对您有所帮助。在工作中,由于客户情况(金融部门),我们几乎在每个表上都有日志表
我们是这样做的:两个表(“正常”表和日志表),然后在插入/更新/删除正常表时触发,正常表存储关键字(I,U,D)和旧记录(更新时,删除)或新记录(插入时)在日志表中
我们在同一个数据库模式中有两个表,这被称为a,研究人员20多年来一直在努力寻找存储和查询时态数据的最佳方法
尝试在执行时存储EAV数据效率低下,因为在文本列中存储数字数据会占用大量空间,而且正如您所发现的,您的表越来越长
另一个选项有时被称为第六范式(尽管6NF有多个不相关的定义),它是存储一个额外的表来存储要临时跟踪的每个列的修订。这类似于@xtrm的答案提出的解决方案,但它不需要存储未更改列的冗余副本。但它确实导致了表格数量的爆炸
我已经开始阅读,它承诺处理结构和内容的时间变化。但我不知道
Should I use another database system, maybe MongoDB?
CREATE TABLE entitychange_somestring (
entity_id INT NOT NULL PRIMARY KEY,
ts TIMESTAMP NOT NULL,
newvalue VARCHAR(50) NOT NULL, -- same type as entity.somestring
KEY(entity_id, ts)
) ENGINE=MyISAM;
CREATE TABLE `entity_versionable` (
`version` INT(11) UNSIGNED NOT NULL AUTO_INCREMENT,
`fk_entity` INT(10) UNSIGNED NOT NULL,
`str1` VARCHAR(255) DEFAULT NULL,
`str2` VARCHAR(255) DEFAULT NULL,
`bool1` TINYINT(1) DEFAULT NULL,
`double1` DOUBLE DEFAULT NULL,
`date` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`version`,`fk_entity`)
) ENGINE=INNODB AUTO_INCREMENT=230297534 DEFAULT CHARSET=latin1
INSERT INTO `entity_versionable` (fk_entity, str1, str2, bool1, double1, DATE)
SELECT 1, 'a1', 238, 2, 524627, '2013-06-16 14:42:25'
FROM
(
SELECT a.N + b.N * 10 + c.N * 100 + d.N * 1000 + e.N * 10000 + f.N * 100000 + g.N * 1000000 + h.N * 10000000 + 1 N FROM
(SELECT 0 AS N UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9) a
,(SELECT 0 AS N UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9) b
,(SELECT 0 AS N UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9) c
,(SELECT 0 AS N UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9) d
,(SELECT 0 AS N UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9) e
,(SELECT 0 AS N UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9) f
,(SELECT 0 AS N UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9) g
,(SELECT 0 AS N UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9) h
) t;