1

我正在创建一个应用程序,其中有主数据库,其他数据存储在辅助数据库中。辅助数据库遵循“插件”方法。我使用 SQL Server。

应用程序的简单安装将只有 mainDB,而作为一个选项,可以激活更多“插件”,并且每个插件都会有一个新数据库。

现在我做出这个选择的原因是因为我必须使用现有的遗留系统,这是我能想到的实现插件系统的最聪明的事情。

MainDB 和 Plugins DB 具有完全相同的架构(基本上,Plugins DB 有一些“特殊内容”,一些可以用作模板的重要数据——例如,在应用程序中考虑一个字母模板)。插件数据库以只读模式使用,它们是“内容存储库”。“聪明”的事情是主应用程序也可以由“插件编写者”使用,他们只需编写一个插入内容的数据库,并通过备份数据库他们创建一个潜在的插件(这就是为什么所有数据库都有相同的架构)。

这些插件数据库是从互联网下载的,因为有可用的内容升级,每次完整的插件数据库被破坏并创建一个具有相同名称的新数据库时。这是为了简单起见,甚至因为这个 DB 的大小通常很小。

现在这行得通,无论如何我更愿意将数据库组织成一种树结构,这样我就可以强制插件数据库成为主应用程序数据库的“子数据库”。

作为一种解决方法,我正在考虑使用命名规则,例如:

ApplicationDB(用于主应用程序 DB)

ApplicationDB_PlugIn_N(用于第 N 个插件 DB)

当我搜索插件 1 时,我尝试连接到 ApplicationDB_PlugIn_1,如果我没有找到数据库,我会引发错误。例如,如果 som DBA 重命名 ApplicationDB_Plugin_1,就会发生这种情况。

因此,由于这些插件数据库实际上仅依赖于 ApplicationDB,因此我试图“做子文件夹技巧”。

谁能建议一种方法来做到这一点?你能评论一下我上面描述的这种自制插件方法吗?

添加信息(开始赏金后):

在 MainDB 中,我计划将连接信息存储到所有插件数据库。基本上它是数据库名称,因为我以一种方式设计系统,即使我使用多个 sql server 登录来访问 MainDB,在幕后也只有一个用户(通常是“sa”或另一个具有管理员权限的用户)。

所以基本上如果我需要查询多个数据库,我将使用数据库名称来区分插件,我不需要在数据库表中显式创建名为 PluginID 的文件。

所以它以某种方式工作,在主数据库中我存储插件数据库名称。所以我知道插件的名称,所以如果我想从所有插件中查询所有 GUNS,我会这样做:

select * from ApplicationDB_Plugin_1.dbo.weapons where weapon_type = 'gun'
union
select * from ApplicationDB_Plugin_2.dbo.weapons where weapon_type = 'gun'
union
select * from ApplicationDB_Plugin_3.dbo.weapons where weapon_type = 'gun'

所以“技巧”是使用 dbname 来区分插件。现在这项工作,但对我来说似乎有点“脏”。我的问题是“你能想到更好的方法吗?”

4

3 回答 3

6

您可以使用模式:

CREATE TABLE mytable (id INT)
GO

CREATE SCHEMA plugin_schema
CREATE TABLE mytable (id INT)
GO

SELECT  *
FROM    dbo.mytable -- selects from the first one

SELECT  *
FROM    plugin_schema.mytable  -- selects from the second one
于 2010-05-20T10:29:09.847 回答
2

如果模式相同,您是否可以在现有表中添加一些内容,以便您可以判断某些数据来自插件 1,而其他数据来自插件 2?您可能会发现将来需要进行“跨插件查询”?

于 2010-05-26T16:32:06.317 回答
1

我可以理解您是如何得出当前解决方案的。保持数据库分开可以清楚哪些数据属于每个插件,并将关注点分开。

尽管它通过一个简单的组织提供了清晰性,但这种方法有一些相当显着的缺点:

  • 不会为每个插件连接到不同的数据库。数据库服务器将运行 N 次查询来查询 N 个插件,因为它必须针对每个插件的单独数据库运行每个查询。

  • 引用完整性不容易在多个数据库(如果有的话)中强制执行,因此您的数据很可能会变得不一致。

  • 降低灵活性和“活力”:创建一个新数据库是一项相当繁重的操作,因此添加一个新插件变得相当繁重。

  • 最后,处理模式更改将很困难 - 如果您有一个尚未更新到最新模式的插件,那么它不能在此方案中使用,因为假定所有数据库都具有相同的结构。

我建议采用混合方法:每个插件继续维护自己的数据库,可以在运行时下载和加载,但不是将应用程序和插件保存在单独的数据库中,而是将插件数据和应用程序 ddata 复制到复合数据库。复合数据库可以在启动时构建,或者在插件集更改时构建,或者在新插件版本可用时构建。这是可行的,因为您提到每个插件数据库都是只读的,而不是更新的。(可以重建数据库,以便保留复合数据库中的应用程序数据。)

当应用程序数据和插件数据集成到一个数据库中时,您可以避免上述问题:

  • 数据库服务器只执行一个查询,而不是每个插件一个

  • 参照完整性是可执行的,因为所有数据都保存在一个数据库中。

  • 最后,也是最重要的,在我看来 - 管理模式更改成为可能。如果有插件没有实现您最新的架构更改,则合并过程可以在将插件数据复制到复合数据库(始终使用最新架构)时调整使用旧架构存储的数据。例如,在复制时使用旧模式的插件,可以为新列添加默认值,可以适应结构的变化,可以删除列/行等。同样的“模式升级”代码也可以提供给插件开发人员以允许他们升级他们的插件架构。

合并过程还可以构建一个“installed_plugins”表,列出复制到复合数据库的所有插件。该表包含有关每个插件的元数据,例如插件更新日期、添加时间、唯一插件 ID 等。

那么,复合数据库是什么样的:

  1. 插件数据存储为单独的表,使用视图将它们组合起来,视图将是每个插件的相应表的并集,加上插件 ID 的列。这将起作用,但不太可能有效。
  2. 给定表类型的插件数据都存储在一起。参照完整性更容易维护,查询也会更快,因为可以在所有插件中使用通用索引。

我的偏好是第二种选择。但是将所有插件数据存储在一起,如何知道每一行来自哪个插件?同样有两种选择:

  1. 使用插件 ID/名称向表中添加一个额外的列。优点是速度快。缺点是它改变了基本模式。
  2. 对于每个表,都有一个伴随表,该表将行 ID 映射到数据来源的插件 ID。查询速度会慢一些,但可以保持核心数据表的架构不受更改。

为简单起见,我的偏好是 1,添加一个 ID 列。由于复合数据库中的表是由脚本或程序构建的,因此任何一种方案都易于实现,因此主要是关于偏好或性能需求,或者合并数据库是否对核心数据表使用与原始应用程序数据库。

我觉得将数据合并在一起是正确的方法,可以减少痛苦、更容易维护、灵活性和更高的性能。但是,如果您仍然有强烈的动机将数据保存在单独的表中,那么至少将它们保存在同一个数据库中,并使用表名前缀或更好的模式名称来保持插件数据命名空间的分离。

祝你好运,无论你选择哪种方式!

于 2010-05-28T17:58:07.553 回答