SQL 设计模式:选择哪一个?

SQL design pattern: which one to choose?

概念:

我有一个 SAAS 应用程序。我有 2-3 个客户,还有更多要关注。每个客户都有自己的数据库,我们的服务器根据登录信息连接到他们。在这些数据库中的每一个上都有一个 table,我们称它为 saas_table,其中包含一个唯一的列:id。每个 table 最多有 3000 行。

我的服务器有一个数据库,其中有一个 table:subscriptions。此 table 包含有关我的客户、他们的数据库凭据等的信息。我想从每个客户数据库中复制 saas_tableid 并将其存储在我的服务器数据库中。

接近?

哪种方法更好:在我服务器的数据库上创建一个巨大的 table log_table 并将记录存储在那里,或者为每个客户创建一个 table log_1_table , log_2_table, 等并存储基于每个客户的信息?我必须指出,假设的 log_* table 将被频繁访问,每个会话至少访问两次。

我认为将 id 存储在单独的 table 上将具有更高的性能,因为 table 将缓存在 RAM 中。但这需要更多的编程,并且可能需要我的应用程序的新核心版本。另一方面,由于每个客户都有流量,来自 log_table 的记录也将被经常访问,因此也缓存在 RAM 中。哪种方法更好?

就个人而言,我永远不会在 tablename 中存储应该存储在列中的信息 - 我认为这是应该存储在列中的信息。每个会话访问 table 两次是相当低的使用率,即使对于成千上万的客户也是如此。我在上一个股票交易平台看到客户每笔交易多次点击table,每小时有数十万笔交易,一个人的交易地位是通过回顾数十亿笔交易并相加得出的找到他们现在的位置。您现在对性能的思考是一种过早的优化,它会分散您的注意力,使您无法关注您正在考虑的更大问题,从而造成工程和维护方面的头痛。

主要是,您忽略了这样一个事实,即 Entity Framework 等更高级别库的大多数 ORM 和数据访问策略旨在将 table 视为包含变量的编译对象类型固定属性(列)的数据(行)。让你建议的每个客户 table 的结构(相同的信息)会让人头疼,比如:

DateTime recentLogin;
if(currentUser == "IBM")
  recentLogin = dbContext.IBMLoginLog.Max(x => x.LoginDate);
elseif(currentUser == "Microsoft")
  recentLogin = dbContext.MicrosoftLoginLog.Max(x => x.LoginDate);
elseif(currentUser == "Facebook")
  recentLogin = dbContext.FacebookLoginLog.Max(x => x.LoginDate);
...

每次添加新客户时,此应用都需要重新编译。本来应该是这样来应对你期待改变的事情):

DateTime recentLogin = dbContext.LoginLog.Where(x => x.User == currentUser).Max(x => x.Logindate);

你可能会说“但我可以对 strSQL = "SELECT MAX(date) FROM " + currentUser + "LoginLog" 做同样的事情,但这是一个意外的副产品,因为你的 SQL 每次都是 运行 并且因此可以应对不断变化的 table 名称 - 这并不表示它是设计程序的明智或好方法,就像您不会编写某些 C# 程序一样,它编写了包含 C# 的文本文件到磁盘,编译它并 运行 它,只是为了更改您正在查找的 table 的名称:

string csharpCode = "...; DateTime recentLogin = dbContext." + currentUser + "LoginLog.Max(x => x.Logindate); ..."
File.WriteAllText(@"c:\temp\getdata.cs", csharpCode);
Process.Start("csc.exe", @"c:\temp\getdata.cs");
Process.Start("c:\temp\getdata.exe");

(这是一个愚蠢的例子;没有人会这样做 - 除了我提倡通过将您的 SQL 串在一起并将其发送到 SQL 服务器,这正是发生)

相反,从 Entity Framework 甚至 SQL 本身中得到启发,因为只有某些东西可以作为参数:

--valid
SELECT MAX(LoginDate) FROM Logins WHERE Client = @clientName

--not valid
SELECT MAX(LoginDate) FROM @clientName+Logins

--valid, but again, that recompiling thing:
EXEC 'SELECT MAX(LoginDate) FROM ' + @clientName + 'Logins'

让你的 table 为客户名称建立索引(并且可能包括你经常需要的其他列的数据,就像这里我可能 CREATE INDEX whatever ON Login(ClientName) INCLUDE (LoginDate) 创建一个可以查看的索引in 对于客户端名称,索引也知道登录日期,因此它可以回答 max(logindate) 查询,而服务器不需要然后点击 table 并检索它从索引中找到的行,以获取日期