我是 Postgres 的新手,我试图了解模式如何适应一切以及非“公共”模式的好处是什么。例如,它是否提供安全性、访问控制优势或其他优势?
我正在使用的设置是 postgres 拥有数据库和表,但向另一个用户授予选择、插入、更新和删除权限。在“公共”模式与“myotherschema”中创建表会有很大区别吗?
我偶然发现了一个我不擅长的数据库设计问题,而我的首选 DBA 大师正在进行消防演习。
本质上,我有一个包含以下主键的表(为简洁起见,PK):
child_id integer
parent_id integer
date datetime
Run Code Online (Sandbox Code Playgroud)
child_id和parent_id是实体表的外键。“子”表本身也包含一个到“父”表的外键,而且,每个表child_id总是引用与parent_id上表预期相同的外键。事实上,事实证明有一些额外的代码使两者保持同步。
这使得这个过度热情的规范化新手说“我应该删除冗余!”
我分解为以下内容:
Table_1 PK:
child_id integer
date datetime
Table_2 PK:
parent_id integer
date datetime
Table_3: (already exists)
child_id integer PRIMARY KEY
parent_id integer FOREIGN KEY
Run Code Online (Sandbox Code Playgroud)
瞧,当我以自然的方式将这些人连接在一起时,我恢复了原始表。这是我的理解,使这个 5NF。
然而,现在我意识到有一个隐藏的商业规则。
通常,与给定关联的日期child_id必须是与相应parent_id. 您可以看到第一个表强制执行此规则。
我的分解不强制执行规则,因为您可以自由添加到表 1,直到日期变得太大。
这使我来到这里,有以下问题:
这是分解5NF吗?虽然我会说它允许插入异常,但它似乎也遵循 Wiki 示例,该示例本身遵循本指南。短语(强调我的)“我们可以从由三种不同记录类型组成的规范化形式重建所有真实事实”给了我特别的停顿,因为无论我注入多少垃圾Table_1,自然连接仍然会忽略它。
假设我不喜欢这种分解(我不喜欢)。我坦率地承认,实际的解决方案是让表格和代码保持原样。但是,从理论上讲,有没有办法分解和/或添加约束,以便我摆脱第一个表并保留我的业务规则?
schema normalization database-design best-practices relational-theory
在我正在处理的一个项目中,必须跟踪对数据库某些表中行的每次更改以进行进一步审计或回滚。必须很容易找到谁修改了行,从哪个 IP 地址和时间,并且能够恢复以前的版本。
例如 Stack Exchange 使用了类似的东西。当我改变别人的问题时,有可能发现我改变了它,并且回滚了改变。
考虑到我当前的架构与普通业务应用程序具有大致相同的属性(如下),用于将每个更改存储在数据库中的通用技术是什么?
nvarchar(1000)例如可能有一些,但不是大量的二进制数据,这个直接存储在磁盘上,直接访问,而不是通过 Microsoft SQL filestream,<tl-博士>
我想过以下案例,但我对这些场景没有真正的经验,所以我想听听其他人的意见:
将所有内容存储在同一个表中,按 ID 和版本区分行。IMO,这是非常愚蠢的,迟早会在性能水平上受到伤害。使用这种方法,也不可能为最新项目和版本跟踪设置不同的安全级别。最后,每个查询的编写都会更加复杂。实际上,要访问最新数据,我将被迫按 ID 对所有内容进行分组,并在每个组中检索最新版本。
将最新版本存储在一个表中,并在每次更改时将过时版本复制到另一个模式中的另一个表中。缺陷是每次我们都会存储每个值,即使它没有改变。设置不变值null不是一个解决方案,因为我还必须当值更改为跟踪null或null。
将最新版本存储在一个表中,并将更改的属性列表及其以前的值存储在另一个表中。这似乎有两个缺陷:最重要的一个是,对同一列中不同类型的先前值进行排序的唯一方法是使用binary(max). 第二个是,我相信,在向用户显示以前的版本时,使用这种结构会更加困难。
执行与前两点相同的操作,但将版本存储在单独的数据库中。在性能方面,为了避免通过将以前的版本放在同一数据库中而减慢对最新版本的访问速度可能会很有趣;尽管如此,我认为这是一个过早的优化,只有在有证据表明在同一数据库中拥有旧版本和最新版本是瓶颈时才必须进行优化。
</tl-dr>
¹ 例如,将更改存储到日志文件中是不可接受的,就像对 HTTP 日志所做的那样,并在服务器负载最低的晚上将数据从日志刷新到数据库中。有关不同版本的信息必须立即或几乎立即可用;几秒钟的延迟是可以接受的。
² 信息不是很频繁,只有特定的用户组才能访问,但是,强迫他们等待 30 秒才能显示版本列表是不可接受的。同样,几秒钟的延迟是可以接受的。
我有一个应用程序(数据存储在 PostgreSQL 中),其中表中的大多数字段始终不为空,但这些表的架构并未强制执行此操作。例如看看这个假表:
CREATE TABLE "tbl" (
"id" serial,
"name" varchar(40),
"num" int,
"time" timestamp
PRIMARY KEY ("id"),
UNIQUE ("id")
);
Run Code Online (Sandbox Code Playgroud)
此外name,num,time没有明确声明为NOT NULL,实际上它们是,因为强制执行发生在应用程序端。
我的感觉是应该改变它,但相反的是应用程序级别确保这里不能出现空值并且没有其他人手动修改表。
我的问题是:通过设置一个显式NOT NULL约束?
我们有一个很好的代码审查流程和一个相当好的文档,所以一些新人会提交打破这个限制的东西的可能性并不足以证明改变是合理的。
这不是我的决定,所以这正是我寻找其他理由的原因。在我看来,如果某些内容不能为空并且数据库允许您指定某些内容不为空 - 那就去做吧。特别是如果更改非常简单。
根据 MS-DOCS about System information schema views,架构列定义有一个警告说明:
**重要** 不要使用 INFORMATION_SCHEMA 视图来确定对象的架构。查找对象架构的唯一可靠方法是查询 sys.objects 目录视图。
为什么不能使用 INFORMATION_SCHEMA 视图来确定对象的架构?
这个信息有误吗?
schema sql-server metadata information-schema sql-server-2017
我使用Git对我的大部分工作进行版本控制:代码、文档、系统配置。我能够做到这一点,因为我所有有价值的工作都存储为文本文件。
我也一直在为我们的 Postgres 数据库编写和处理很多 SQL 模式。该模式包括视图、SQL 函数,我们将用R编程语言(通过PL/R)编写 Postgres 函数。
我试图复制和过去我和我的合作者编写的块模式,但我忘记这样做了。复制和过去的动作是重复的并且容易出错。
pg_dump / pg_restore 方法将不起作用,因为它会丢失注释。
理想情况下,我希望有某种方法将我当前的模式提取到一个或多个文件中并保留注释,以便我可以进行版本控制。
带注释的版本控制架构的最佳实践是什么?
每当我在 PostgreSQL Maestro 中创建一个全新的数据库时,它都会创建以下默认模式列表:

现在根据我的理解,模式就像组织文件夹等。所以我的问题是当我创建新数据库时是否需要所有这些模式?如果是这样,它们在 PG 方面用于什么,因为我自己永远不会使用它们。
我可以理解,information_schema因为这是在服务器上安装 MySQL 的默认设置,尽管我不明白为什么数据库需要它自己而不是整个服务器,但我猜每个数据库类型都有他自己的。
我继承了一个应用程序,它将许多不同类型的活动与一个站点相关联。大约有 100 种不同的活动类型,每一种都有不同的 3-10 个字段集。但是,所有活动都至少有一个日期字段(可以是日期、开始日期、结束日期、预定开始日期等的任意组合)和一个负责人字段。所有其他字段差异很大,开始日期字段不一定称为“开始日期”。
为每个活动类型制作一个子类型表将导致一个包含 100 个不同子类型表的模式,这将过于笨拙而无法处理。该问题的当前解决方案是将活动值存储为键值对。这是当前系统的一个大大简化的架构,可以理解这一点。

每个Activity有多个ActivityFields;每个 Site 有多个 Activity,SiteActivityData 表存储每个 SiteActivity 的 KVP。
这使得(基于 Web 的)应用程序非常容易编写代码,因为您真正需要做的就是遍历 SiteActivityData 中给定活动的记录,并为表单的每一行添加一个标签和输入控件。但是有很多问题:
所以我正在寻找一种方法来存储大量几乎没有共同字段的活动,从而使报告更容易。到目前为止,我想出的是使用 XML 以伪 noSQL 格式存储活动数据:

Activity 表将包含每个活动的 XSD,从而无需 ActivityField 表。SiteActivity 将包含键值 XML,因此站点的每个活动现在都在一行中。
一个活动看起来像这样(但我还没有完全充实它):
<SomeActivityType>
<SomeDateField type="StartDate">2000-01-01</SomeDateField>
<AnotherDateField type="EndDate">2011-01-01</AnotherDateField>
<EmployeeId type="ResponsiblePerson">1234</EmployeeId>
<SomeTextField>blah blah</SomeTextField>
...
Run Code Online (Sandbox Code Playgroud)
好处:
select ... from ActivityXML.nodes('/SomeActivityType/*') as T(r)select ActivityXML.value('.[@type=StartDate]', 'datetime') as StartDate, …注意:我指的是数学序列,而不是PostgreSQL的序列机制。
我有一个表示整数序列的表。定义是:
CREATE TABLE sequences
(
id serial NOT NULL,
title character varying(255) NOT NULL,
date date NOT NULL,
sequence integer[] NOT NULL,
CONSTRAINT "PRIM_KEY_SEQUENCES" PRIMARY KEY (id)
);
Run Code Online (Sandbox Code Playgroud)
我的目标是使用给定的子序列查找行。也就是说,sequence字段是包含给定子序列的序列的行(在我的情况下,序列是有序的)。
假设该表包含以下数据:
+----+-------+------------+-------------------------------+
| id | title | date | sequence |
+----+-------+------------+-------------------------------+
| 1 | BG703 | 2004-12-24 | {1,3,17,25,377,424,242,1234} |
| 2 | BG256 | 2005-05-11 | {5,7,12,742,225,547,2142,223} |
| 3 | BD404 | 2004-10-13 | {3,4,12,5698,526} |
| …Run Code Online (Sandbox Code Playgroud) 我想创建一个发布配置文件,它可以进行完整的架构比较和发布,但不会删除在新旧版本之间删除的任何表或任何列。
我知道设置中的阻止可能的数据丢失选项。AFAIK 这会停止发布过程,以防数据丢失。所以问题是,模式升级过程会被中断(在不知何故?)还是会完成但受影响的表将被排除在外?
如果表已添加和删除列,新列是否会添加到架构中,尽管由于潜在的数据丢失而阻止数据丢失选项会停止架构更新?
编辑 09.08.2016:
我想添加这些链接以补充有关背景的其他信息的问题:
schema ×10
postgresql ×5
sql-server ×3
array ×1
deployment ×1
metadata ×1
null ×1
optimization ×1
performance ×1
reporting ×1
ssdt ×1