场景:多个客户都将创建存储在“CustomerObject”表内的“对象”。让我们说它看起来像这样:
CustomerObject :
ID bigint
CustomerID bigint
Type int
JSONDynamicProperties nvarchar(max)
环境:
我的问题是关于绩效和最佳做法:
在什么时候(如果有的话)为每个客户提供他们自己的对象表而不是让所有对象都在同一个表中?
拥有1000个或更多的表会产生更多的性能影响,而不是每个人都会在一个表中拥有5到7千万行吗?
使用Entity Framework Core时,我是否可以使用不同的表来对CustomerObject数据模型进行水合,具体取决于哪个Customer正在运行查询?
你能想到的任何其他直接陷阱会浮现在脑海中吗?
感谢您提供的任何指导!
答案 0 :(得分:2)
使用不同的架构,SQL Azure / SQL Server可能会做得更好。实际上,您使用所提议的设计整天阅读和编写大型BLOB,与更优化的逻辑和物理数据库设计模式相比,您的性能可能会成为IO的瓶颈。 (换句话说,在这种情况下,执行代码优先技术的代码很快,执行速度也慢一些。)
我将首先尝试回答您的基本问题,但需要注意的是,您可能希望以不同的方式解决此问题:
Re:1表与N表:SQL Server和SQL Azure创建查询计划并缓存它们。在某些情况下,这些计划的编译可能会很昂贵,因此通常使用相同的模式来减少具有相同模式的表以减少SQL中的编译开销。 (除了JSON blob之外,你还没有真正完成一个模式,读取和编写blob的开销可能远远不是最优的,直到你在应用程序中解决这个问题。)
Re:1000个表与1个大表:假设您已经完成了正确的索引,SQL可以拥有一个具有数十亿行而不会出汗的搜索客户模式的表。因此,由于编译开销,您不需要1000个表,但是您希望确保您的查询都在寻找足够特定的内容以避免IO(逻辑或物理),以便您的应用程序在最佳状态下表现良好/接近。 / p>
Re:EF +从多个表加载:我不是EF专家(我是SQL专家),但我相信这个问题会因为我对1 + 2的回答而消失。
现在,我将尝试为您提供有关如何更有效地解决问题的指导。由于您在SQL Azure中为性能付费,因此您可以通过允许以较小的数据库预留大小运行来节省资金。
您可以尝试两种主要模式,它们依赖于您是否具有开放模式或固定模式。如果您允许客户在该JSON blob(开放模式)中创建任意值,您可能需要考虑属性包或实体属性值(EAV)模式。这看起来像: CREATE TABLE EAV(CustomerID bigint,Attribute nvarchar(100),Value sqlvariant) 然后,您希望在customerid,attribute。
上创建聚簇索引如果您需要阅读所有内容,此模式将允许您使用索引搜索读取特定值或扫描整个客户的属性。这些值将大致并置在磁盘上,更新只会为数据执行IO,并为您触摸的属性的子集执行日志。 (NVarchar(max)确实支持部分写入,但是如果我不得不猜测它是如何最容易实现的话,EF很可能每次都会读取和写入整个blob。)
如果您想要一次更新许多属性,那么EAV模式并不那么容易,因为您需要写出N个更新语句或一个更大的属性来更新一组行。
如果您有一组已知的列,则最好为每个列创建一个包含列的表。 (SQL也有一个“稀疏”列属性,可用于大量空列)。这允许您在需要时为每个字段编制索引,并允许更复杂的应用程序(在get-put应用程序之外)执行良好。因此,如果您想搜索星期二的客户销售额并且超过一定金额,则此架构模式允许索引模型,使这些查询运行良好(假设正在使用b树索引)。
请注意,SQL Server / SQL Azure也支持表分区。对于非常大的表,您可以获得使用分区的管理优势。但是,如果您已正确索引此类应用程序,则很可能不需要对主线数据访问性能进行分区,因为所有内容都可以是索引搜索。
希望有所帮助! 康纳坎宁安 架构师,SQL核心引擎