问题 在实体上存储更改:MySQL是否是正确的解决方案?


我想存储我在“实体”表上所做的更改。这应该像一个日志。目前它在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 NULL DEFAULT 'STRING_1',
  `when` TIMESTAMP NOT NULL,
  `value` TEXT,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
  • entity_id =我的主键 entity 表。
  • entitytype =在中更改的字段 entity 表。有时只改变一个字段,有时多个。一个变化=一行。
  • value =字段“新值”的字符串表示形式。

更改字段时的示例 entity.somedouble 从3到2,我运行这些查询:

UPDATE entity SET somedouble = 2 WHERE entity_id = 123;
INSERT INTO entitychange (entity_id,entitytype,value) VALUES (123,'SOMEDOUBLE',2);

我需要 select 过去15天内特定实体和实体类型的变化。例如:最后一次更改 SOMEDOUBLE for entity_id 123 在过去15天内。

现在,有两件事我不喜欢:

  1. 所有数据都存储为 TEXT  - 虽然大多数(小于1%)不是真正的文本,但就我而言,大多数值都是 DOUBLE。这是一个大问题吗?
  2. 由于表已经有2亿行,因此插入时表变得非常非常慢。目前我的服务器负载高达10-15。

我的问题: 我如何解决这两个“瓶颈”?我需要扩展。

我的方法是:

  1. 像这样存储: http://sqlfiddle.com/#!2/df9d0 (点击浏览) - 将更改存储在 entitychange 表然后根据其数据类型存储该值 entitychange_[bool|timestamp|double|string]
  2. 使用分区 HASH(entity_id)  - 我想到了~50个分区。
  3. 我应该使用其他数据库系统,也许是MongoDB?

1572
2018-06-11 16:29


起源

正确的正规化(使用数据类型)不是一个选项? - Strawberry
我会说同样的,不知道为什么你使用枚举,你应该使用至少两个表,日志一个和另一个表的实体类型。在主日志表中,entitytype表的foreing键。 - xtrm
由于您有一个包含5个值的枚举,因此您将拥有一个实体类型表,总共有32条记录(2 ^ 5 = 32)。 entitytype表中的每条记录都有自己的id,在主日志表中只有一个简单的foreing_key。您将节省大量空间并使JOIN快速。另一种方法,如果我们正确使用规范化,将在entitytype表中设置'entity foreing key',并从主日志表中删除entitytype。最后,我建议测试性能。 - xtrm
我还建议删除第一个id列,并将主键设置为entity_id而不使用AUTOINCREMENT。这将节省更多空间。此外,由于它将成为主键,因此它将被编入索引,您的搜索查询将更快。我建议添加另一个适合您要搜索的字段的索引。 dev.mysql.com/doc/refman/5.6/en/mysql-indexes.html - xtrm
@xtrm:感谢您的评论,但我不能将entity_id用作主键,因为我可以更改,比方说, SOMEDOUBLE 来自同一个实体,从而生成两行 entitychange 与此相同 entity_id。我更新了我的问题,因此“改变过程”变得更加清晰。 - Stefan


答案:


如果我遇到你提到的问题,我会像下面那样设计LOG表:

  1. EntityName:(String)正在被操纵的实体。(必填)
  2. ObjectId:正在被操纵的实体,主键。
  3. FieldName:(字符串)实体字段名称。
  4. OldValue:(String)实体字段旧值。
  5. NewValue:(String)实体字段的新值。
  6. UserCode:应用程序用户唯一标识符(强制)
  7. TransactionCode:任何更改实体的操作都需要具有唯一的事务代码(如GUID)(强制),
     如果实体更新了多个字段,这些列将成为跟踪更新中所有更改(交易)的关键点
  8. ChangeDate: 交易日期。 (强制)
  9. FieldType:枚举或文本显示字段类型,如TEXT或Double。 (强制)

有这种方法
 可以跟踪任何实体(表)
报告是可读的
仅记录更改。
 事务代码将是通过单个操作检测更改的关键点。

BTW

Store the changes in the entitychange table and then store the value 
according to its datatype in entitychange_[bool|timestamp|double|string]

不需要,在单个表中您将拥有更改和数据类型

Use partitioning by HASH(entity_id)

我更喜欢通过ChangeDate进行分区或为changeDate创建备份表,这些备份表已经足够大,可以从主LOG表中备份和卸载

Should I use another database system, maybe MongoDB?

任何数据库都有自己的概率和缺点,您可以在任何RDBMS上使用该设计。 基于文档的数据库(如MongoDB)的有用比较 可以在这里找到

希望有所帮助。


5



谢谢你的回答。为什么 FieldType 需要吗? - Desprit
它可能对将来的解释使用很方便。想想是否对阵列进行了更改或...... - Mohsen Heydari


现在我想我明白了你需要的东西,一个可更改记录历史的可版本表。这可能是实现相同目标的另一种方法,您可以轻松地进行一些快速测试,以确定它是否比您当前的解决方案提供更好的性能。它是Symfony PHP Framework在Doctrine中使用Versionable插件的方式。
请记住,有两个键的主键唯一索引,版本和fk_entity。
另请查看保存的值。您将在未更改的字段中保存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))
);


可能是提高性能的另一个步骤,可能是将所有历史记录日志记录保存在单独的表中,每月一次左右。这样你在每个表中都不会有很多记录,按日期搜索会非常快。


3



谢谢你的回答,但我不确定存储整行会提高性能。比方说,在我的生产环境中,我有30个专栏,而且大多数只有一个专栏发生了变化,我认为保存所有内容并不好,包括大 TEXT 领域。还是我错了? - Stefan


这里有两个主要挑战:

  1. 如何有效地存储数据,即占用更少的空间和易于使用的格式

2-3。管理大表:归档,便于备份和还原

2-3。性能优化:更快的插入和选择

有效地存储数据 

  1. value 提起。我建议去做 VARCHAR (N)。 原因:

    • 由于数据类型的原因,使用N <255将每行节省1个字节。
    • 使用此字段的其他数据类型:固定类型使用空间,无论值是什么,通常每行8个字节(日期时间,长整数,字符(8)),其他变量数据类型对于此字段来说太大。
    • TEXT 数据类型会导致性能损失:(来自manaul on BLOB和Text数据类型

实例 TEXT 使用临时表处理的查询结果中的列会导致服务器在磁盘而不是内存中使用表,因为MEMORY存储引擎不支持这些数据类型。使用磁盘会导致性能下降,因此只有在确实需要时才在查询结果中包含BLOB或TEXT列。例如,避免使用选择所有列的SELECT *。

每个BLOB或TEXT值在内部由单独分配的对象表示。这与所有其他数据类型形成对比,在打开表时,每列分配一次存储。

基本上 TEXT 用于存储大字符串和拼接文本,而 VARCHAR() 是设计相对较短的字符串。

  1. id 领域。 (更新,感谢@steve)我同意这个字段没有任何有用的信息。使用3列作为主键: entity_id 和 entitype 和 when 。 TIMESTAMP 我会很好地保证你不会重复。同样的列也将用于分区/子分区。

表可管理性 有两个主要选项:MERGE表和分区。 MERGE存储引擎基于My_ISAM,据我所知,它正在逐步淘汰。以下是[MERGE存储引擎]的一些阅读。2

主要工具是分区,它提供两个主要好处: 1.分区切换(通常是对大块数据的即时操作)和滚动窗口场景:在一个表中插入新数据,然后立即将所有数据切换到存档表中。 2.按排序顺序存储数据,启用分区修剪 - 仅查询包含所需数据的分区。 MySQL允许子分区进一步分组数据。

分区 entity_id 说得通。如果您需要长时间查询数据,或者在查询表时有其他模式 - 请使用该列进行子分区。除非在该级别切换分区,否则不需要对所有主键列进行子分区。

分区数取决于您希望该分区的db文件的大小。子分区数量取决于核心数量,因此每个核心可以搜索自己的分区,N-1子分区应该可以,所以1核心可以做整体协调工作。

优化

插入:

  • 在没有索引的情况下,表上的插入更快,因此插入大块数据(执行更新),然后创建索引(如果可能)。

  • 更改 Text 对于 Varchar  - 数据库引擎需要一些压力

  • 最小的日志记录和表锁可能有所帮助,但通常不可能使用

选择:

  • Text 至 Varchar 绝对应该改善一切。

  • 有一个包含最新数据的当前表 - 过去15天,然后通过分区切换移动到存档。在这里,您可以选择将表分区与归档表不同(例如,先按日期,然后是entity_id),并通过将小(1天)数据移动到临时表以及更改分区来更改分区方式。

您还可以考虑按日期分区,您在日期范围内有很多查询。首先使用您的数据及其部件,然后确定哪种架构最能支持它。

至于你的第三个问题,我不知道如何使用MongoDB特别有利于这种情况。


2



id 字段:使用 (entity_id,when) 如 PRIMARY KEY 没有用,因为一个实体可以同时在这个表中进行两次更改(例如,每行为 SOMEBOOL 和 SOMEDOUBLE 使用相同的时间戳) - 使用 (entity_id,when,entitytype) 代替? - Stefan
@steve,如果几个字段可以在这里同时改变 - 那么是的。聚集索引是表本身,因此使密钥更长不会占用任何额外空间。 - Stoleg
你能否说出保存这些变化的(dis)优点: sqlfiddle.com/#!2/df9d0  - 正如我的方法#1中所述? - Stefan
@steve这个任务太过分了。规范化结构对于实体管理是有益的,但对于归档来说过度,并且使用连接减慢查询。您需要考虑使用数据然后应用最佳模型来支持它,而不是规范化到3级或5级所有内容。评论太短,无法提供详细的分析。 - Stoleg
@steve例如:varchars总是使用至少1-2个字节,即使对于NULL,somedouble总是使用8个字节(NOT NULL)和somebool 1个字节,枚举已经在数据库引擎中进行了规范化,只有JOIN所需的其他表。由于使用该表的方式,不会利用这种结构的好处。 - Stoleg


这被称为a 时态数据库20多年来,研究人员一直在努力寻找存储和查询时态数据的最佳方法。

尝试存储EAV数据时效率很低,因为在TEXT列中存储数字数据会占用大量空间,并且您的表越来越长,正如您所发现的那样。

另一个有时被称为第六范式的选项(虽然有6NF的多个不相关的定义),是存储一个额外的表来存储修订 对于每一列 你想暂时跟踪。这类似于@ xtrm的答案提出的解决方案,但它不需要存储未更改的列的冗余副本。但它确实导致了桌子数量的激增。

我已经开始阅读了 锚建模,它承诺处理结构和内容的时间变化。但我还不太清楚它的解释。我只是链接到它,也许它对你有意义。

以下是一些包含时态数据库讨论的书籍:


1





在a中存储整数 TEXT 专栏是禁止的! TEXT 是最昂贵的类型。

我会为每个要监视的字段创建一个日志表:

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;

实际上是对它们进行分区。

注意我建议使用 MyISAM 发动机。您不需要此(这些)无约束,仅插入表的事务。


1





为什么INSERTing如此缓慢,你可以做些什么来加快速度。

这些是我要看的东西(大致按照我将通过它们的顺序):

  1. 创建一个新的AUTO_INCREMENT-id并将其插入主键需要一个锁(InnoDB中有一个特殊的AUTO-INC锁,它在语句结束前一直保持,有效地充当了 桌锁 在你的场景中)。这通常不是问题,因为这是一个相对较快的操作,但另一方面,当(Unix)加载值为10到15时,您可能会有进程等待释放该锁。根据您提供的信息,我认为您的代理键'id'没有任何用处。查看删除该列是否会显着改变性能。 (顺便说一句,没有规则表需要一个主键。如果你没有一个,那没关系)

  2. 对于INSERT,InnoDB可能相对昂贵。这是为了允许诸如交易之类的附加功能而进行的权衡,可能会或可能不会影响您。由于您的所有操作都是原子的,因此我认为不需要进行交易。也就是说,试试MyISAM吧。注意:对于大型表,MyISAM通常是一个糟糕的选择,因为它只支持表锁定而不是记录级别锁定,但它确实支持 并发插入,所以它可能是一个选择(特别是如果你放弃主键,见上文)

  3. 您可以使用数据库存储引擎参数。 InnoDB和MyISAM都有可以改变的选项。其中一些对TEXT数据的实际存储方式有影响,另一些则具有更广泛的功能。你应该特别注意的是 的innodb_flush_log_at_trx_commit

  4. 如果(并且仅当)它们具有非NULL值,则TEXT列相对昂贵。您目前正在存储 所有 TEXT列中的值。值得尝试下面的内容:添加额外的字段 value_int 和 value_double 到您的表并将这些值存储在相应的列中。是的,这将浪费一些额外的空间,但可能会更快 - 但这在很大程度上取决于数据库存储引擎及其设置。请注意,很多人对TEXT列性能的看法并不正确。 (看到 我对VARCHAR与TEXT相关问题的回答

  5. 您建议在多个表中传播信息。如果您的表完全独立,这只是一个好主意。否则,对于任何更改,您最终都会有多个INSERT操作,并且您很可能会使事情变得更糟。虽然归一化数据通常是好的(tm),但这可能会损害性能。

你能做些什么来让SELECT快速运行

  1. 正确的钥匙。和正确的钥匙。以防我忘记提及:正确的钥匙。您没有详细说明您的选择是什么样的,但我认为它们类似于“SELECT * FROM entitychange WHERE entity_id = 123 AND ts> ...”。 entity_id和ts上的单个复合索引应该足以使此操作快速。由于必须使用每个INSERT更新索引,因此可能值得尝试两者的性能 entity_id, ts 和 ts, entity_id:它可能会有所作为。

  2. 分区。如果你没有在问题中提问,我甚至不会提起这个问题。你没有说你为什么要分区表。在性能方面,如果你有合适的密钥,它通常没有区别。有一些特定的设置可以提高性能,但你需要适当的硬件设置来配合这一点。如果您决定对表进行分区,请考虑使用entity_id或TIMESTAMP列进行分区。使用时间戳,最终可能会将归档系统与旧数据放​​在归档驱动器上。然而,这样的分区系统需要一些维护(随着时间的推移添加分区)。

在我看来,你并不关心查询性能和原始插入速度,所以我不会详细介绍SELECT性能。如果您对此感兴趣,请提供更多详细信息。


1



我需要选择一定的统计数据 entity_id 和 entitytype 组合,也许吧 (entity_id, entitytype, when) 将是一个很好的主键。我还需要在过去两周内选择参赛作品,所以归档可能是一个好主意,对吧?我需要所有数据,但不会定期查询超过两周的数据。 - Stefan
你的复合键听起来不错。请记住,维护索引会增加插入的工作量。尝试将其作为辅助(非唯一)密钥和主键,并查看是否会产生重大影响。如果你想分区 when,请注意 when 列必须是主键的一部分,最好是其第一列, (when, entity_id, entitytype) - Hazzit


我建议你在深度测试中做很多工作,但是从我的测试中我用INSERT和SELECT获得了非常好的结果,我之前发布了表定义。我将详细介绍我的测试,以便任何人都可以轻松地重复并检查它是否会获得更好的结果。 在任何测试之前备份您的数据。
我必须说这些只是测试,可能不会反映或改善你的实际情况,但它是一种很好的学习方式,可能是一种寻找有用信息和结果的方法。

我们在这里看到的建议非常好,你肯定会注意到通过使用大小而不是TEXT的预定义类型VARCHAR来提高速度。但是你可以获得速度,我建议不要因为数据完整性原因而使用MyISAM,请留在InnoDB。

测试:

1.设置表并插入2亿个数据:






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

为了在约35分钟的表格中插入+200万行,请检查我的其他问题在哪里 peterm 已回答其中一个 填写表格的最佳方法。它完美地运作。

执行以下查询2次,以插入2亿行无随机数据(每次更改数据以插入随机数据):

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;


*由于您已拥有包含2亿行真实随机数据的原始表,因此您可能不需要填充它,只需导出表数据和模式并将其导入具有相同模式的新测试表中。这样,您将在新表中使用您的真实数据进行测试,并且您获得的改进也适用于原始数据。



2.更改新测试表的性能 (或者在步骤1中使用我上面的示例来获得更好的结果)。 一旦我们有了新的测试表设置并填充了随机数据,我们应该检查上面的建议,并更改表格以加快它:

  • 将TEXT更改为VARCHAR(255)。
  • 选择并创建一个包含两个或三个的主键唯一索引 列。在第一个版本中使用版本自动增量和fk_entity进行测试 测试。
  • 必要时对表进行分区,并检查它是否提高了速度。一世 建议不要在你的第一次测试中对它进行分区,以便 通过更改数据类型和mysql来检查实际性能增益 组态。检查以下链接 分区和 改进提示
  • 优化和修复您的桌子。索引将再次进行,并将 速度搜索很多:

优化表 testentity_versionable;
  修理表 testentity_versionable;   
  *制作一个脚本来执行优化并使您的索引保持最新,每晚启动它。


3.改进MySQL和硬件配置 仔细阅读以下主题。他们值得一读,我相信你会得到更好的结果。
 

  • 轻松提高您的数据库硬盘配置花费一点
    钱:如果可能的话,使用SSD作为主MySQL数据库,以及a
    独立机械硬盘用于备份目的。设置MySQL日志 保存在另一个第三个硬盘上以提高你的速度
    插入。 (记得在一些之后对机械硬盘进行碎片整理 周)。
  • 绩效链接: 一般与多芯组态优化IODebiancores最好的配置配置48gb ram..
  • 分析SQL查询: 如何配置查询检查查询中是否存在瓶颈
  • MySQL非常耗费内存,如果使用低延迟CL7 DDR3内存 可能。有点偏离主题,但如果你的系统数据很关键,你可能会寻找ECC内存,但价格昂贵。


4.最后,测试测试表中的INSERT和SEARCH。 我使用上面的表模式测试了带有200万随机数据的测试,它花了0,001秒来插入新行,大约2分钟来搜索和选择1亿行。然而它只是一个测试,似乎是好结果:)


5.我的系统配置:

  • 数据库: MySQL 5.6.10 InnoDB数据库(测试)。
  • 处理器: AMD Phenom II 1090T X6核心,每核心3910Mhz。
  • 内存: 16GB DDR3 1600Mhz CL8。
  • 高清: SSD中的Windows 7 64位SP1,安装在SSD中的mySQL,用机械硬盘写的日志。
    可能我们应该得到更好的结果,其中一个最新的英特尔i5或i7轻松超频到4500Mhz +,因为 MySQL只为一个SQL使用一个核心。核心速度越高,执行速度越快。

6.阅读有关MySQL的更多信息:
O'Reilly高性能MySQL
MySQL优化SQL语句


7.使用其他数据库: MongoDB或 Redis的 对于这种情况将是完美的,可能比MySQL快很多。两者都很容易学习,两者都有其优点:
- MongoDB: MongoDB日志文件增长

Redis的

我肯定会去 Redis的。如果您学习如何在Redis中保存日志,那么这将是以极快的速度管理日志的最佳方式: redis用于记录
如果您使用Redis,请记住以下建议:

  • Redis是用C编译的,它存储在内存中,有一些不同 自动将信息保存到磁盘的方法 (坚持),你可能不必担心它。 (万一发生灾难 场景你将结束大约1秒的日志记录)。

  • Redis用于许多管理数TB数据的站点, 有很多方法可以处理疯狂的信息量 它意味着它的安全(在这里用于stackoverflow,暴雪,推特,你的...)

  • 由于你的日志非常大,它需要适合内存 无需访问硬盘即可获得速度。你可以 保存不同日期的不同日志,并仅设置其中一些日志 记忆。在达到内存限制的情况下,你不会有任何错误,一切仍然可以正常工作,但检查 Redis Faqs 了解更多信息。

  • 我完全相信Redis会比这更快 MySQL的。您将需要了解如何玩 lists 和 sets 更新数据和查询/搜索数据。如果您可能需要真正高级的查询搜索,那么您应该使用MongoDB,但在这种情况下,简单的日期搜索将非常适合Redis。

Nice Redis的文章 Instagram博客。 


1





在工作中,由于客户条件(金融部门),我们几乎在每张桌子上都有日志。

我们这样做了:两个表(“普通”表和日志表)然后触发正常表的插入/更新/删除,它们存储关键字(I,U,D)和旧记录(更新时) ,删除)或新的一个(插入时)在logtable中

我们在同一个数据库模式中有两个表


0