【问题标题】:SQL design pattern: which one to choose? [duplicate]SQL 设计模式:选择哪一种? [复制]
【发布时间】:2020-02-20 09:30:10
【问题描述】:

概念:

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

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

接近?

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

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

【问题讨论】:

  • 这是一个常见问题解答。在考虑发布之前,请始终在谷歌上搜索任何错误消息或您的问题/问题/目标的许多清晰、简洁和精确的措辞,带有和不带有您的特定字符串/名称和站点:stackoverflow.com 和标签;阅读许多答案。如果您发布问题,请使用一个短语作为标题。请参阅How to Ask 和投票箭头鼠标悬停文本。
  • 工程中没有“更好”/“最好”之类的东西,除非定义它。同样不幸的是,所有合理的实际定义都需要大量的经验,以及与对细节的混乱敏感度相互作用的大量因素。进行简单的设计。当您通过测量证明您可以想到的设计和所有替代方案都存在问题时(无论当时意味着什么),然后提出一个非常具体的问题。这也应该定义“更好”/“最好”。 Strategy for “Which is better” questions

标签: sql database-design


【解决方案1】:

就个人而言,我永远不会将应该存储在列中的信息存储在表名中 - 我认为这是应该存储在列中的信息。每个会话访问一个表两次的使用率相当低,即使对于成千上万的客户也是如此。我工作的最后一个股票交易平台会看到客户每笔交易多次敲击许多表,每小时有数十万笔交易,一个人的交易地位是通过回顾数十亿笔交易并求和以找到他们当前的位置来计算的.您现在对性能的思考是一种过早的优化,它会分散您对更大问题的注意力,因为您正在考虑造成工程和维护方面的麻烦。

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

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 每次运行时都是从字符串编译的,因此可以应对不断变化的表名 - 这不是表明这是设计程序的明智或好方法,就像您不会编写一些 C# 程序一样,将包含 C# 的文本文件写入磁盘,编译并运行它,只是为了更改名称您正在查看的表:

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 Server 之外,这正是正在发生的事情)

取而代之的是,从 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'

有你的一个表,索引客户名称(并且可能包括您经常想要的数据的其他列,就像这里我可能 CREATE INDEX whatever ON Login(ClientName) INCLUDE (LoginDate) 创建一个可以查找客户名称的索引,以及index 知道登录日期,因此它可以回答 max(logindate) 查询,而无需服务器随后点击表并从索引中检索它找到的行来获取日期

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-08-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-04-23
    相关资源
    最近更新 更多