使用多个数据库各自具有一个模式,还是使用一个数据库具有多个模式更好?

Posted

技术标签:

【中文标题】使用多个数据库各自具有一个模式,还是使用一个数据库具有多个模式更好?【英文标题】:Is it better to use multiple databases with one schema each, or one database with multiple schemas? 【发布时间】:2010-11-12 06:01:13 【问题描述】:

在this comment 回答我的一个问题之后,我在考虑是否最好使用一个具有 X 架构的数据库,反之亦然。

我正在开发一个网络应用程序,当人们注册时,我(实际上)创建了一个数据库(不,它不是一个社交网络:每个人都必须有权访问自己的数据,并且永远不会看到其他用户的数据) .这就是我在以前版本的应用程序中使用的方式(仍在 mysql 上运行):通过 Plesk API,对于每次注册,我都会这样做:

    创建具有有限权限的数据库用户; 创建一个只能由之前创建的用户和超级用户访问的数据库(用于维护) 填充数据库

现在,我需要对 PostgreSQL 做同样的事情(项目正在变得成熟,而 MySQL 并不能满足所有需求)。我需要让所有数据库/模式备份独立:pg_dump 在这两种方式下都能完美运行,对于可以配置为仅访问一个模式或一个数据库的用户也是如此。

那么,假设您是比我更有经验的 PostgreSQL 用户,您认为对我的情况最好的解决方案是什么,为什么?使用 $x 数据库而不是 $x 模式会有性能差异吗?未来有什么解决方案会更好地维护(可靠性)?我所有的数据库/模式将始终具有相同的结构!

对于备份问题(使用 pg_dump),最好使用一个数据库和多个模式,一次转储所有模式:恢复将非常简单,将主转储加载到开发机器中,然后仅转储和恢复模式需要:还有一个额外的步骤,但转储所有架构似乎比一个一个转储更快。

2012 年更新

嗯,在过去两年中,应用程序的结构和设计发生了很大变化。我仍在使用“一个具有多个模式的数据库” - 方法,但我的应用程序的每个版本都有一个数据库

Db myapp_01
    \_ my_customer_foo_schema
    \_ my_customer_bar_schema
Db myapp_02
    \_ my_customer_foo_schema
    \_ my_customer_bar_schema

对于备份,我会定期转储每个数据库,然后将备份移动到开发服务器上。我也在使用 PITR/WAL 备份,但正如我之前所说,我不可能一次恢复 所有数据库。所以它可能会在今年被解雇(在我的情况下不是最好的方法)。

从现在开始,one-db-many-schema 方法对我来说效果很好,即使应用程序结构完全改变了。我几乎忘记了:我所有的数据库/模式将总是具有相同的结构!现在,每个模式都有自己的结构,可以根据用户数据流动态变化。

【问题讨论】:

"我所有的数据库/模式都将具有相同的结构!"你的意思是它们都具有相同的结构?还是从不? 对不起,是的,它们永远都具有相同的结构:如果我改变一个,我会改变所有的;) 如果您有 1000 个客户,这意味着您必须更新 1000 个架构? @jpartogi:是的,但我必须只更新表结构,而不是数据。 那么,你最后是为了什么?一个问题,虽然查询等的性能可以由表空间控制,但模式导致多数据库与多模式的等效性能,对 WAL 日志有任何影响吗??? 【参考方案1】:

我会说,使用多个数据库和多个模式 :)

PostgreSQL 中的模式很像 Oracle 中的包,以防您熟悉它们。数据库旨在区分整个数据集,而架构更像是数据实体。

例如,您可以使用“UserManagement”、“LongTermStorage”等模式为整个应用程序创建一个数据库。然后“UserManagement”将包含“User”表,以及用户管理所需的所有存储过程、触发器、序列等。

数据库是整个程序,模式是组件。

【讨论】:

... 所以我将有 1 个数据库,在模式内部:$customer1_user_schema、$customer2_user_schema、$customer3_user_schema、$customer1_documents_schema、$customer2_documents_schema、$customer3_documents_schema?嗯......似乎不是一种可靠的方式......性能呢?那么我的应用程序的代码(将是 php 和 python)呢?这么多模式.. @Strae:我将其解读为:每个客户都有自己的数据库 customer1_database、customer2_database,在这些数据库中您有 user_schema、documents_schema。【参考方案2】:

一些模式应该比一些数据库更轻量级,尽管我找不到证实这一点的参考。

但是,如果您真的希望将事物保持独立(而不是重构 Web 应用程序以便将“客户”列添加到您的表中),您可能仍然希望使用单独的数据库:我断言您可以更轻松地以这种方式恢复特定客户的数据库,而不会打扰其他客户。

【讨论】:

【参考方案3】:

PostgreSQL“模式”与 MySQL“数据库”大致相同。在 PostgreSQL 安装上拥有许多数据库可能会出现问题;拥有许多模式将毫无困难。因此,您肯定希望在该数据库中使用一个数据库和多个模式。

【讨论】:

这个。 Postgres 不允许您跨数据库查询,这可能很烦人。 “在 PostgreSQL 安装上安装许多数据库可能会出现问题”——请澄清;它是一般问题还是在这种特定情况下有问题,为什么? “在数据库中使用多个模式的最常见用例是构建软件即服务应用程序,其中每个客户都有自己的模式。虽然这种技术看起来很有吸引力,但我们强烈建议不要因为它导致了许多操作问题的案例。例如,即使是中等数量的模式(> 50)也会严重影响 Heroku 数据库快照工具的性能“devcenter.heroku.com/articles/heroku-postgresql @NeilMcGuigan:有趣的是,这似乎与 kquinn(已接受)的答案相反。 拥有一个包含多个模式的数据库将使得几乎不可能转储其中的一个模式。我正在运行具有超过 3000 个模式的单个 postgres 数据库,如果您尝试转储单个模式,pg_dump 只会因内存不足错误而失败。我想知道如果我有 3000 个数据库,这是否会有所不同。【参考方案4】:

当然,我会选择 one-db-many-schemas 方法。这使我可以转储所有数据库,但可以通过多种方式非常轻松地仅恢复一个:

    转储数据库(所有架构),将转储加载到新数据库中,仅转储我需要的架构,然后在主数据库中恢复。 一个一个地单独转储架构(但我认为机器会以这种方式遭受更多损失 - 我预计会有 500 个架构!)

否则,谷歌搜索我发现没有自动程序来复制模式(使用一个作为模板),但许多人建议这样:

    创建模板模式 当需要复制时,用新名称重命名 转储 重命名 恢复转储 魔法完成了。

我已经用 Python 写了两行来做到这一点;我希望他们可以帮助某人(在 2 秒内编写代码,不要在生产中使用它):

import os
import sys
import pg

# Take the new schema name from the second cmd arguments (the first is the filename)
newSchema = sys.argv[1]

# Temperary folder for the dumps
dumpFile = '/test/dumps/' + str(newSchema) + '.sql'

# Settings
db_name = 'db_name'
db_user = 'db_user'
db_pass = 'db_pass'
schema_as_template = 'schema_name'

# Connection
pgConnect = pg.connect(dbname= db_name, host='localhost', user= db_user, passwd= db_pass)

# Rename schema with the new name
pgConnect.query("ALTER SCHEMA " + schema_as_template + " RENAME TO " + str(newSchema))

# Dump it
command = 'export PGPASSWORD="' + db_pass + '" && pg_dump -U ' + db_user + ' -n ' + str(newSchema) + ' ' + db_name + ' > ' + dumpFile
os.system(command)

# Rename back with its default name
pgConnect.query("ALTER SCHEMA " + str(newSchema) + " RENAME TO " + schema_as_template)

# Restore the previous dump to create the new schema
restore = 'export PGPASSWORD="' + db_pass + '" && psql -U ' + db_user + ' -d ' + db_name + ' < ' + dumpFile
os.system(restore)

# Want to delete the dump file?
os.remove(dumpFile)

# Close connection
pgConnect.close()

【讨论】:

【参考方案5】:

在 PostgreSQL 上下文中,我建议使用一个具有多个模式的数据库,因为您可以(例如)跨模式使用 UNION ALL,但不能跨数据库。因此,一个数据库实际上与另一个数据库完全隔离,而模式与同一数据库中的其他模式并不隔离。

如果您将来 - 出于某种原因 - 必须跨架构整合数据,那么跨多个架构执行此操作将很容易。对于多个数据库,您将需要多个数据库连接,并通过应用程序逻辑“手动”收集和合并来自每个数据库的数据。

后者在某些情况下具有优势,但在大多数情况下,我认为单数据库多模式方法更有用。

【讨论】:

【参考方案6】:

我建议不要接受接受的答案 - 多个数据库,而不是多个架构,原因如下:

    如果您正在运行微服务,您希望在您的“模式”之间强制无法加入,这样数据就不会纠缠在一起,开发人员也不会最终加入其他微服务的模式并想知道为什么当其他团队做出改变时,他们的东西就不再起作用了。 如果您的负载需要,您以后可以轻松迁移到单独的数据库计算机。 如果您需要设置高可用性和/或复制,最好使用彼此完全独立的独立数据库。与整个数据库相比,您不能只复制一个架构。

【讨论】:

完全取决于服务。请注意,这是一个很老的问题;但是该服务最终需要在两个“微服务”之间进行查询(最初项目中没有)。使用模式让它变得很容易,如果我不记得错了,只是更好地配置数据库用户的权限。如果我们选择“N 个数据库”的方式,那会有点困难(但绝对可能) 现在的方法会有所不同,可能会暴露某种 API 维护完全分离的数据库/模式。 @Strae,你是对的,这是一个老问题,但是,我只是想把它重新提出来,并希望对同一个问题有所了解。我做了一些研究,决定投入 10 美分。 是的,欢迎您这样做!根据我的经验,(就我的情况而言)差别不大;使用 1 db 和多个模式有助于备份和跨模式查询【参考方案7】:

使用具有多个架构的单个数据库是很好的方法 在 postgres 数据库中练习,因为:

    在 postgres 中没有跨数据库共享任何数据。 到服务器的任何给定连接都只能访问单个数据库中的数据,即连接请求中指定的数据。

使用多个模式:

    允许多个用户使用一个数据库而不会互相干扰。 将数据库对象组织成逻辑组,使其更易于管理。 可以将第三方应用程序放入单独的架构中,这样它们就不会与其他对象的名称发生冲突。

【讨论】:

以上是关于使用多个数据库各自具有一个模式,还是使用一个数据库具有多个模式更好?的主要内容,如果未能解决你的问题,请参考以下文章

使用具有多个 DB 模式但使用一个 DBContext 的 Entity Framework 6

组合模式

使用 Impala 选择具有通配符模式的多个表并将它们连接起来

我应该在 DAL 中使用哪种设计模式,同时拥有具有不同模型的多个数据库源?

使用 Cayenne 从具有多个模式的 Postgres 数据库生成类

具有多个 MySql 模式的实体框架多个 DbContext