我们有一个SQL服务器,每个客户端都有一个数据库,我们有数百个客户端。想象一下:database001,database002,database003,...,database999。我们希望将所有这些数据库合并到一个数据库中。
我们的想法是添加一个siteId列,001,002,003,...,999。
我们正在探索尽可能顺利完成转换的方案。我们很乐意听到您的任何想法。它被证明是一个非常具有挑战性的问题。
我听说过一种可以创建匹配然后过滤的视图的技术。
任何想法的人?
答案 0 :(得分:7)
为每个客户端数据库创建客户端数据库ID。您将使用此id来保持数据在逻辑上分开。这是“站点ID”概念,但您可以使用派生密钥(标识字段)而不是手动创建这些数字。创建一个具有数据库名称和标识的表,以及您需要的任何其他元数据。
下一步是创建一个SSIS包,该包获取相关数据库的ID,并将其添加到必须将其数据逻辑分离的表中。然后,您可以在每个数据库上运行相同的包,并查找相关数据库的ID。
如果您拥有唯一且唯一且已导入数据的ID,则必须更改您的应用以适应新架构(实际上之前,或者您几乎搞砸了)。
如果要逐步执行此操作,可以在不同的“数据库”中创建视图或函数,以便旧客户端仍然可以访问客户端的数据,即使它已被移动。如果部署一些停机时间,则可能不需要此步骤。
我建议的方法相当灵活,可以一次应用于一个客户端,具体取决于您的客户端应用程序部署方法。
答案 1 :(得分:4)
为什么要这样做?
您可以阅读有关Multi-Tenant Data Architecture的内容,并聆听有关此设计的SO #19 (around 40-50 min)。
答案 2 :(得分:3)
“site-id”解决方案已经完成了。
另一种可能无法解决的可能性(但仍然很吸引人)是单个数据库中的多个模式。您可以将公用表拉入“通用”模式,并将客户特定的内容保留在客户特定的模式中。但是,在某些数据库产品中,每个模式 - 实际上 - 是一个单独的数据库。在其他产品(例如Oracle,DB2)中,您可以轻松编写在多个模式中工作的查询。
另请注意 - 作为优化 - 您可能不需要将siteId
列添加到每个表中。
有时你会有“包含”关系。它是一个主要细节FK,通常使用级联删除定义,以便在没有父级的情况下不能存在细节。在这种情况下,孩子们不需要siteId,因为他们没有独立的存在。
答案 3 :(得分:3)
您的第一步是确定这些数据库是否具有相同的结构。即使你认为他们这样做,你也需要比较它们以确保它们能够做到。可能会有一些定制或错过一两个升级周期。
现在,根据客户端数量和每个客户端的记录数量,您的表格可能会变得很大。您确定这不会产生性能问题吗?无论如何,您可能需要重新审视索引。您可能需要一组功能更强大的服务器,并且可能还需要客户端分享以提高性能。
接下来,是的,每个表都需要某种类型的站点ID。此外,根据您的设计,您可能拥有现在不再唯一的主键。您可能需要重新定义所有主键以包含siteid。添加时始终为此字段编制索引。
现在需要重写所有查询,存储过程,视图和udfs,以确保siteid是其中的一部分。特别注意任何动态SQL。否则,您可能会向客户B显示客户A的信息。客户不喜欢这样。我们将客户从一个单独的数据库带到主应用程序一次(当他们决定他们不想再为单独的服务器付费时)。开发人员错过了一个必须添加client_id的地方。不幸的是,这会向每个客户发送有关此客户专有信息的电子邮件,并且更糟糕的是,这是一个在半夜运行的夜间过程,因此直到第二天才知道。 (开发人员非常幸运,不会被解雇。)当你这样做并进行测试,测试,测试和测试时,要非常小心。确保在幕后测试所有自动化内容以及UI内容。
答案 4 :(得分:3)
我在去年年底在佛罗伦萨解释的是,如果你必须保持数据库名称和数据库的逻辑层与应用程序相同。在这种情况下,您将执行以下操作:
答案 5 :(得分:1)
如果数据很大,您可以查看使用分区视图。这将简化您的访问代码,因为您需要维护的只是视图;但是,如果数据不大,只需添加一列来标识客户。
答案 6 :(得分:1)
根据数据和您的安全要求,交叉污染的威胁可能是一个显示阻止。
假设您已经考虑过这一点,并认为它“足够安全”。您可能需要/想要创建VIEWS或强加一些其他访问控制以防止客户看到彼此的数据。
IIRC一个名为“Trusted Oracle”的产品能够根据这样的密钥对数据进行分区(大约是Oracle 7或8发布的时间)。这个想法是任何给定的查询都会自动附加“和sourceKey = @userSecurityKey”(或某些此类)。该功能可能已被纳入流行商业产品的更高版本。答案 7 :(得分:0)
为了扩展Gregory的答案,你还可以创建一个父ssis来调用在foreach循环容器中实际移动的包。
父包查询配置表并将其放入对象变量中。然后,foreach循环使用此记录集将变量传递给包,例如数据库名称和包可能需要的任何其他详细信息。
您可以列出所有客户端数据库,并在准备好移动它们时标记一个标记。这样您就不会在32,767数据库上运行ssis包。我迷上了ssis的foreach循环。