Postgresql:最好使用多个数据库,每个数据库有1个模式,还是1个数据库有多个模式?

Str*_*rae 133 database postgresql database-design database-permissions

在对我的一个问题发表评论之后,我在想是否更好地使用带有X架构的1个数据库,反之亦然.

我的情况:我正在开发一个网络应用程序,当人们注册时,我创建(实际上)数据库(不,它不是社交网络:每个人都必须能够访问自己的数据,永远不会看到其他用户的数据).

这就是我用于我的应用程序的先前版本(仍然在mysql上运行)的方式:通过plesk api,对于每次注册,我这样做:

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

现在,我需要对postgresql做同样的事情(项目越来越成熟,mysql ......不能满足所有需求)

我需要使所有数据库/模式备份独立:pg_dump在两种方式下都能很好地工作,对于可以配置为仅访问1个模式或1个数据库的用户来说是相同的.

所以,假设你是比我更有经验的potgres用户,你认为对我的情况最好的解决方案是什么,为什么?

使用$ x db而不是$ x schemas会有性能差异吗?什么解决方案将来会更好地维护(可靠性)?

编辑:我差点忘了:我所有的数据库/模式将始终具有相同的结构!

Edit2:对于备份问题(使用pg_dump),使用1 db和多个模式可能更好,一次性转储所有模式:恢复将非常简单地在dev机器中加载主转储然后转储和恢复所需的模式:还有1个额外的步骤,但是倾倒所有架构似乎更快,然后逐个转储它们.

ps:对不起,如果我在文本中忘记了一些'W'字符,我的键盘会受到该按钮的影响;)

更新2012年

那么,应用程序的结构和设计在过去的两年中发生了很大变化.我仍在使用这种one db with many schemas方法,但是,我的应用程序的每个版本都有1个数据库:

Db myapp_01
    \_ my_customer_foo_schema
    \_ my_customer_bar_schema
Db myapp_02
    \_ my_customer_foo_schema
    \_ my_customer_bar_schema
Run Code Online (Sandbox Code Playgroud)

对于备份,我定期转储每个数据库,然后在开发服务器上移动备份.

我也使用PITR/WAL备份,但正如我之前所说,它不太可能我必须立即恢复所有数据库 ..所以它可能会被解雇今年(在我的情况下不是最好的方法).

从现在开始,1-db-many-schema方法对我来说非常有效,即使应用程序结构完全改变了:

我差点忘了:我所有的数据库/模式将始终具有相同的结构!

...现在,每个模式都有自己的结构,可以改变对用户数据流的反应.

kqu*_*inn 102

PostgreSQL"模式"与MySQL"数据库"大致相同.在PostgreSQL安装上安装许多数据库可能会出现问题; 有很多架构将毫无困难地工作.因此,您肯定希望在该数据库中使用一个数据库和多个模式.

  • "在PostgreSQL上安装许多数据库可能会出现问题" - 请澄清; 一般来说还是在这种特殊情况下有问题,为什么? (75认同)
  • "在数据库中使用多个模式的最常见用例是构建一个软件即服务应用程序,其中每个客户都有自己的模式.虽然这种技术看起来很引人注目,但我们强烈建议不要使用它,因为它导致了大量的操作问题.例如,即使是中等数量的模式(> 50)也会严重影响Heroku数据库快照工具的性能"https://devcenter.heroku.com/articles/heroku-postgresql (29认同)
  • 这个.Postgres不允许您跨数据库查询,这可能非常烦人. (27认同)
  • @NeilMcGuigan:有趣的是,这似乎是与kquinn(已接受)答案相反的结论. (11认同)
  • 对于那些在2015年底阅读它的人.现在有一个`dblink` Postgres扩展用于跨数据库查询(这是对@mattb评论的回复). (7认同)
  • 但是,拥有一个具有许多模式的数据库将使得几乎不可能转储这些模式的单个模式.我正在运行一个包含超过3000个模式的postgres数据库,如果您尝试转储单个模式,pg_dump只会因内存不足而失败.我想知道如果我有3000个数据库,这会有什么不同. (7认同)
  • 深入研究,这是一篇关于此事的相当有趣的文章 https://influitive.io/our-multi-tenancy-journey-with-postgres-schemas-and-apartment-6ecda151a21f 和 https://rob.conery。 io/2014/05/28/a-better-id-generator-for-postgresql/ 解决了您可能遇到的一些问题。第一篇文章也有一条评论,该评论与 Josh Berkus 的多模式多表问题相关(https://medium.com/@jberkus/you-dont-say-above-what-version-s-of-postgresql -you-used-e3d84e5ad33) (4认同)
  • @mattb对于那些在2014年之后阅读它的人,Pg具有从v9.3开始的外部数据包装器,尤其是`postgres_fdw`允许跨Pg数据库进行查询(IMO比`dblink`更好)。 (3认同)

Str*_*rae 26

当然,我会选择1-db-many-schemas方法.这允许我转储所有数据库,但在很多方面非常容易地恢复1:

  1. 转储db(所有模式),在新数据库中加载转储,只转储我需要的模式,并在主db中恢复
  2. 逐个转储模式(但我认为机器会受到更多这样的影响 - 我期待500个模式!)

否则,谷歌搜索我已经看到没有自动程序来复制架构(使用一个作为模板),但许多建议这样:

  1. 创建模板架构
  2. 需要复制时,请使用新名称重命名
  3. 转发它
  4. 重新命名
  5. 恢复转储
  6. 魔术完成了.

我在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()
Run Code Online (Sandbox Code Playgroud)


小智 11

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

postgres中的模式很像Oracle中的软件包,以防您熟悉这些模式.数据库旨在区分整个数据集,而模式更像数据实体.

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

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

  • @Strae:我读的是:每个客户都有它的数据库customer1_database,customer2_database,在这些数据库中你有user_schema,documents_schema. (7认同)
  • ...所以我将拥有1个数据库,其中包含模式:$ customer1_user_schema,$ customer2_user_schema,$ customer3_user_schema,$ customer1_documents_schema,$ customer2_documents_schema,$ customer3_documents_schema?...... ......似乎不是一种可靠的方式......那么性能呢?那我的应用程序的代码(将是php和python)呢?这么多架构...... (4认同)

Ala*_*reb 7

我建议不要接受已接受的答案 -由于这组原因,使用多个数据库而不是多个模式:

  1. 如果您正在运行微服务,您希望强制无法在您的“架构”之间加入,因此数据不会纠缠在一起,开发人员最终不会加入其他微服务的架构,并想知道为什么其他团队不再更改他们的东西作品。
  2. 如果您的负载需要轻松,您可以稍后迁移到单独的数据库机器。
  3. 如果您需要设置高可用性和/或复制,最好拥有彼此完全独立的单独数据库。与整个数据库相比,您不能仅复制一个模式。

  • 我最喜欢的答案。我们不应该假设允许跨模式查询是一件好事,事实上我们应该从相反的假设开始! (9认同)
  • 完全取决于服务。请注意,这是一个很老的问题;但该服务最终需要在两个“微服务”之间进行查询(这不在最初的项目中)。使用模式使它变得有点简单,如果我不记得错误的话,只是更好地配置数据库用户的权限的问题。如果我们选择“N 个数据库”方式,那就会有点困难(但绝对有可能) (2认同)
  • 现在的方法会有所不同,可能会公开某种将数据库/模式完全分离的 API。 (2认同)

ema*_*max 6

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

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

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


Tro*_*vin 5

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

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