MultiTenant表是否应在主键和外键中包含TenantID?

问题描述 投票:16回答:2

对于多租户单共享数据库,tenantid字段是否应包含在主键和聚簇索引中?还是像性能一样在tenantid上添加附加索引?

我们在唯一索引是主键上的聚集索引的生产系统上遇到性能问题。

所有sql select语句在其linq to实体语句中以tenantid开头,例如

invoiceitems.tenantid = thecurrenttenantid order by invoicedate

当前方案

Tenant(tenantid uniqueidentifier主键,tenantname)外键(tenantid)索引(聚集在tenantid上)

客户(tenantid uniqueidentifier,customerid uniqueidentifier主键,客户名varchar(50))外键(tenantid,customerid)索引(聚集在customerid上>]]

发票(tenantid uniqueidentifier,invoiceid uniqueidentifier主键

,billcustomerid uniqueidentifier,shipcustomerid uniqueidentifier,invoicedate日期时间)外键(tenantid,billcustomerid,shipcustomerid)索引(聚集在发票上]

InvoiceItems(tenantid uniqueidentifier,invoiceitemid uniqueidentifier主键

,invoiceid uniqueidentifier,lineitemorder int)外键(tenantid,发票)索引(聚集在发票上]]

SqlAzure要求每个表都有一个聚集索引,因此它是默认值,因此目前仅在primarykeyid上。现在,这是每个表上的唯一索引。整个系统的表中都有各种外键,并且没有索引任何外键表字段。

我们正在尝试解决一些性能问题,并想知道什么是最佳的聚集索引,以及是否还有其他索引可能会有所帮助。我们希望除非绝对必要,否则我们不必更改现有的聚集索引,但我们愿意这样做。在SqlAzure AFAIK中,您不能简单地调整现有表中的聚簇索引-您必须创建具有所需聚簇索引的新表并将所有记录从旧表插入到新表中(并处理所有外键约束和其他表依赖性)。

所有sql select语句以tenantid开头

在它们的linq to实体语句中。
invoiceitems.tenantid = thecurrenttenantid order by invoicedate

某些sql select语句仅具有顺序-引入子表时,某些具有其他联接条件值,例如

invoiceitems.tenantid = thecurrenttenantid and invoice.invoiceid = invoiceitems.invoiceid order by invoicedate

这里有一些想法(除此之外,我们还对其他人开放)-其中哪一个最好,为什么

主键索引选项

为了加快对租户记录的访问

选项1-在tenantid上添加非聚集索引

发票(tenantid uniqueidentifier,invoiceid uniqueidentifier主键,billcustomerid uniqueidentifier,shipcustomerid uniqueidentifier,invoicedate datetime)外键(tenantid,billcustomerid,shipcustomerid)索引(聚集在发票上,非聚集在tenantid

选项2-将主键从primaryid更改为tenantid + primaryid,并将聚集索引更改为tenantid + primaryid。

发票(tenantid uniqueidentifier主键,invoiceid uniqueidentifier主键,billcustomerid uniqueidentifier,shipcustomerid uniqueidentifier,invoicedate日期时间)外键(tenantid,billcustomerid,shipcustomerid)索引(聚集在tenantid +发票上的发票

外键索引选项

要加快加入速度

选项3-仅在外键上的所有外键字段上添加非聚集索引。

发票(tenantid uniqueidentifier,invoiceid uniqueidentifier主键,billcustomerid uniqueidentifier,shipcustomerid uniqueidentifier,invoicedate datetime)外键(tenantid,billcustomerid,shipcustomerid)索引(聚集在发票上,非聚集在billcustomerid上,非聚集在shipcustomerid)]

选项4-将所有外键从Foreignkeyid更改为tenantid + foreignkeyid,并在tenantid + foreignkeyid上添加索引

发票(tenantid uniqueidentifier,invoiceid uniqueidentifier主键,billcustomerid uniqueidentifier,shipcustomerid uniqueidentifier,invoicedate datetime)外键(tenantid,tenantid + billcustomerid,tenantid + shipcustomerid)索引(在发票上群集,在tenantid + billcustomerid上非群集,在tenantid + shipcustomerid上非群集

]]

SQL SELECT优化索引选项

要加快常用查询,例如从发票中选择字段,其中tenantid =发票日期的值顺序

选项5-在除tenantid之外的每个表中最常用的排序顺序字段上添加索引。

发票(tenantid uniqueidentifier,invoiceid uniqueidentifier主键,billcustomerid uniqueidentifier,shipcustomerid uniqueidentifier,invoicedate datetime)外键(tenantid,billcustomerid,shipcustomerid)索引(聚集在发票上,非聚集在发票上]

选项6-在每个表中在tenantid +“最常用的排序顺序字段”上添加索引,并在tenantid +“最常用的排序顺序字段”上添加非聚集索引。

发票(tenantid uniqueidentifier,invoiceid uniqueidentifier主键,billcustomerid uniqueidentifier,shipcustomerid uniqueidentifier,invoicedate datetime)外键(tenantid,billcustomerid,shipcustomerid)索引(聚集在发票上,非聚集在tenantid +发票上

对于多租户单共享数据库,tenantid字段是否应包含在主键和聚簇索引中?还是在tenantid上添加附加索引以达到性能?我们正在运行...

似乎您已经给出了很多想法。不管我或其他人说什么,唯一可以确定的方法就是自己测量。在这种情况下,这不再是SQL Azure问题,而是更多的常规SQL Server查询优化问题。

针对您的情况,有一些提示可以帮助您入门。使用LINQ时,您无法直接访问在SQL中运行的实际查询。您可能认为您知道查询的外观,但是根据您使用的EF版本,它可以对如何构造查询做出一些有趣的决定。要确切了解正在运行的查询,您将需要使用SQL Profiler或Extended Events。 SQL Profiler不适用于SQL Azure,因此您要么需要使用扩展事件,要么需要在本地的本地服务器上获取数据库的副本,然后运行指向本地的应用程序。 SQL Server Management Studio(SSMS)中的export data tier application和相关的import为此非常有用。

通过实际查询,您可以在SSMS中针对Azure中的数据库运行它们,以获取执行计划。然后,您可以更改索引,再次运行查询并比较计划。如果您不想弄乱您的主要开发数据库,​​则可以使用in a number of ways轻松创建一个副本,包括使用CREATE DATABASE xxx AS COPY OF yyyy命令。

不要试图在本地数据库上进行优化。与大多数内部安装的SQL相比,SQL Azure的性能概述有所不同。

话虽如此,如果您的all

个查询总是将包含租户ID,那么是的,我希望将其作为聚簇索引的第一部分会改善您的查询性能。对于所有其他索引,我不太确定,因此要进行测量,测量和测量。还请记住,索引不是免费提供的,创建的每个索引都会影响写入性能以及数据库的大小,因此我不会胡乱地为所有内容建立索引。

最后,如果您的数据库足够大,您需要按租户ID联合它(您的结构看起来将很好地处理它),IDENTITY列将不再是一种选择。] >

我同意@knigtpfhor的回答,但是要补充一点,如果您打算在SQL Azure中使用联合身份验证,则需要将联合身份验证密钥(TenantID)作为联合身份验证成员中每个表的聚集索引的一部分包括在内。 (您上面的选项2)。有关更多详细信息,请参见Federation Guidelines and Limitations

我绝对会在您的表上添加其他非聚集索引;选择要索引的字段是一门科学和一门艺术,但是我通常会先从检查可能发出的查询开始,并确保我有一个涵盖所涉及字段的索引。我的直觉是,虽然对您的主\外键进行了索引,但它们可能在所有情况下都与您实际查询数据的方式无关。

您遇到什么样的性能问题?您在写数据或查询数据或同时遇到这两个问题吗?有问题的数据库有多大?您的绩效问题是断断续续还是相当一致?

database-design azure indexing azure-sql-database multi-tenant
2个回答
2
投票

似乎您已经给出了很多想法。不管我或其他人说什么,唯一可以确定的方法就是自己测量。在这种情况下,这不再是SQL Azure问题,而是更多的常规SQL Server查询优化问题。

针对您的情况,有一些提示可以帮助您入门。使用LINQ时,您无法直接访问在SQL中运行的实际查询。您可能认为您知道查询的外观,但是根据您使用的EF版本,它可以对如何构造查询做出一些有趣的决定。要确切了解正在运行的查询,您将需要使用SQL Profiler或Extended Events。 SQL Profiler不适用于SQL Azure,因此您要么需要使用扩展事件,要么需要在本地的本地服务器上获取数据库的副本,然后运行指向本地的应用程序。 SQL Server Management Studio(SSMS)中的export data tier application和相关的import为此非常有用。


0
投票

我同意@knigtpfhor的回答,但是要补充一点,如果您打算在SQL Azure中使用联合身份验证,则需要将联合身份验证密钥(TenantID)作为联合身份验证成员中每个表的聚集索引的一部分包括在内。 (您上面的选项2)。有关更多详细信息,请参见Federation Guidelines and Limitations

我绝对会在您的表上添加其他非聚集索引;选择要索引的字段是一门科学和一门艺术,但是我通常会先从检查可能发出的查询开始,并确保我有一个涵盖所涉及字段的索引。我的直觉是,虽然对您的主\外键进行了索引,但它们可能在所有情况下都与您实际查询数据的方式无关。

您遇到什么样的性能问题?您在写数据或查询数据或同时遇到这两个问题吗?有问题的数据库有多大?您的绩效问题是断断续续还是相当一致?

© www.soinside.com 2019 - 2024. All rights reserved.