Improve this question
我的问题:我计划在数据库中存储一个“项目”,其中一个项目由多个项目组成,例如文件,而每个文件都有多个项目,例如段落。段落可能会交叉引用其他文档中的段落。存在许多团队,每个团队可能有许多项目。团队成员编辑,更新和完善交叉引用文档的位置,直到他们满意为止,然后再在该位置查看文档或项目。
签发文档时,审阅后,签发状态将保留,并且任何更改都会更改为新的暂存/当前状态。
发布项目时,将对其进行全面审查和发布。然后将文档集,内容和交叉引用保留在该期中,以便在整个项目中捕获状态。然后,随后的所有编辑都将应用于新的暂存/当前版本,使发行的集可以像发行时一样被读取。
我考虑过使用典型的数据库设置,但是担心a)存储的行数会迅速增长; b)找到“当前”集合或任何特定项目的集合将过于复杂/脆弱,无法可靠使用。
作为变型,将文档存储在例如单个文档行中的JSON阻止了分段段落的传播,而不会造成较大的性能损失?
另一种想法是为每个项目分配一个Git存储库。但随后又担心存储和性能,并且不得不将“文档”存储为例如JSON文档或类似文件,以使系统有效地工作。然后,您还需要为每个登录的用户管理每个会话的暂存区域,这很慢-是吗?除了GitHub,GitLab等之外,还可以快速访问仓库历史记录...
最初将通过Web应用程序访问数据库(或等效数据库)。最终,如果遵循该路径,则可以通过API将其提供给本地客户端,甚至允许本地客户端使用git repos。理想情况下,将使用PHP或NodeJS易于访问的技术。
特定问题-如何/应如何存储和访问需要配置控制的多个相关工件?
参考方案
TL; DR
您在此处公开的模型是关系数据库的非常清楚的用例。将文本存储在数据库中不会出现明显的性能问题,并且即使您确实设法解决数据库IO瓶颈,如今服务器资源也非常便宜,尽管几乎可以肯定任何瓶颈都在您的代码中,而不是在数据库操作中。
大纲
首先,我将揭露为什么我认为事件源和nosql不适合的想法,然后再探讨一种可能的方法来对您所说的域进行建模,最后列举一些如何执行任何操作的示例。
不是事件来源
我首先想到了事件源,因为它很容易管理事件的演变,例如编辑段落,查看问题等。
但是,在尝试对其进行建模时,这似乎是不切实际的,因为要避免在每次咨询问题时都需要重播整个事件链,则必须将快照保存在数据库/缓存系统中。同时支持问题的定时快照和事件源发现并不能算是成功。
不是Nosql数据库
我相信nosql数据库实际上在这里显然是亏损的。您所谈论的一切都是完全,绝对,相关的。域的结构似乎从未改变,因此您不会从nosql灵活性中受益。
对关系数据库是
因此,我认为传统的关系型sql数据库设置在这里应该完全是首选。
我在处理相对大量的文本(非常类似于具有多个任意长的段落的文档)方面有第一手经验,并且对行进行乘法没有任何问题。它们的确会成倍增加,特别是如果您跟踪历史记录时,这就是关系数据库的用途,它处理大量数据。
数据库暂定模型
我认为这里提到的大多数实体都可以直接建模。简单来说,我的意思是说有几个标准字段:
- ID
-parent_id(当实体是子代时,例如段落)
-time_created:时间戳
-time_updated:时间戳
一些dbms在行更新时提供时间戳字段的自动更新
基于此,这可能是一个段落结构。请注意,状态为此处,它很可能位于paragraph_revision
表中,例如,支持在首次发布某段后对其进行进一步的修订。甚至可能两者兼有,因为我们稍后会看到它的用途。
段
-段落编号
-document_id
-created_at
-状态(to_be_reviewed,in_review,已审核,已拒绝,可变)
-顺序(也许,如果需要文档中的特定顺序)
但是请小心,因为这种情况有些棘手。由于我们希望拥有所有更改及其作者的详细历史记录,因此该段落的实际内容在另一个表中,该表链接到原始(单个)段落实体。请注意,只有一个created_at
时间戳记值。在这种范例中,段落修订永远不会更新,而会创建新的修订。数据库触发器或其他技巧可以用来实现此目的。
段落修订
-段落编号
-created_at
-文字
-标题(如果需要)
-版本号
可能可以使用基于简单整数的修订版号
-author_id
本段引用可以保证另一个多对多关系表。要获取所有一个段落引用,请select referenced_paragraph_id from paragraph_reference where paragraph_id = :id
或通过切换列来选择所有引用特定段落的段落。在这里,您可以引用一般段落或段落的特定修订版本,以免丢失历史记录。
段落参考
-段落编号
-referenced_paragraph_id
问题似乎是一个项目,一个或多个文档,每个文档由一个或多个段落组成。基本上,一个issue
表,一个链接到单个问题的issue_document
表和一个包含特定issue_paragraph
id的paragraph_revision
表链接到这些issue_document
表。文档表可以删除,因为所有段落都是文档的子级,但是我更喜欢能够直接选择内容,而不是从其子级中选择它们。
问题
-issue_id
-时间戳
issue_document
-issue_id
-document_id
issue_paragraph
-document_id
-段落内容编号
UUID可能是相关的
这可能是对实体使用uuid而不是数字id的有效情况,尤其是当增长使得必须复制数据库或能够在将其发送到数据库之前创建有效实体时尤其如此。
外键不是可选的
虽然不太复杂,但这是一个有点花哨的架构。外键不是一个选择。每个父ID必须具有一个外键,数据库完整性必须由数据库引擎来强制执行,否则它将变得脆弱。使用外键,这样的稍微复杂的系统可以并且将随着时间的推移保持一致。
管理域动作
希望我给出的有关如何创建表的几个示例可以使您对总体结构有所了解,现在给出一些具体的示例,说明如何在不同的用例中实现该结构。
创建一个项目
相当简单:在project
表中添加一行,无需任何其他操作。
创建一个段落
需要添加两行:一行将唯一标识paragraph
中的段落,另一行包含paragraph_revision
中的内容。
更新段落
在paragraph_revision
表中添加了一行。如果人们每5秒钟保存一次,则可能可以使用和更新一个条目,直到用户做出“我对此版本没问题”操作为止。 (这使它成为“不更新修订版”规则的唯一例外。可以使用其他技巧,例如temp_paragraph_revision
表。)
查看段落
选择paragraph_revision
的编号最高的修订版将使您看到要查看的当前版本。可以通过选择特定paragraph_id
的所有内容来创建所有修订的列表。设置审阅后,状态会在paragraph
和paragraph_revision
表中更新,这可能会阻止进行任何修订,或者如果添加了修订,则会重置审阅状态。
发布段落或项目
在问题表中创建一行,将文件链接到issue_document表中的问题,将paragraph_revision
链接到issue_paragraph
表中的这些文件。可以在此处进行选择,即在此issue_paragraph
表中包括修订的实际内容,以确保在出现问题后不能更改段落内容,但是如果从不更改则使用更新版本,没有必要。
结论
尽管这似乎是要事先创建很多表,但其中大多数表都很小,而好的UML图可以消除大多数表上的犹豫。为此使用联接,请确保将索引保留在这些联接中使用的列上。所有这些都可以在大多数sql发行版,MariaDB和MySQL中实现,也可以在postgres中实现。
我已在数据库中使用datetime字段存储日期,使用PHP将“今天的日期”插入该字段的正确方法是什么?干杯, 参考方案 我认为您可以使用php date()函数
PHP getallheaders替代 - php我正在尝试从服务器上的apache切换到nginx。唯一的问题是我在PHP脚本中使用的getallheaders()函数,该函数不适用于Nginx。我已经尝试过用户在getallheaders函数上的php站点上提供的注释,但这并不返回所有请求标头。请告诉我如何解决这个问题。我真的想切换到Nginx。 参考方案 您仍然可以使用它,但是您必须像这里一样重新定义…
PHP mysqli获取查询返回的第一行的值 - php我正在使用mysqli从数据库中获取某些数据。我正在使用的查询已设置为仅从数据库返回一行。有没有一种方法可以在不使用while循环的情况下获取该行的值?我知道一个while循环对于返回多于一行的行很有用,但是如果不需要while循环,我想避免这种情况,因为不必要的代码是不好的编程。 参考方案 是的-您可以使用:$row = $result->fetch…
php Singleton类实例将在多个会话中保留吗? - php举一个简单的例子,如果我想计算一个不使用磁盘存储的脚本的命中次数,我可以使用静态类成员来执行此操作吗?用户1:<?php $test = Example::singleton(); $test->visits++; ?> 用户2:<?php $test = Example::singleton(); $test->visits+…
更改默认的URL PHP - php如何更改默认网址。例如www.example.com/index.php-> www.example.com现在,我要将其设置为www.example.com/test.php。我应该在php.ini中进行更改吗? 参考方案 假设您正在使用apache,则可以通过DirectoryIndex指令执行此操作。Check out the docs。