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

DkD*_*Dev 15 indexing database-design azure multi-tenant azure-sql-database

对于多租户单个共享数据库,tenantid字段是否应包含在主键和聚簇索引中?或者在tenantid上添加额外的索引,就像表现一样?

我们在生产系统上遇到性能问题,其唯一索引是主键上的聚簇索引.

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

invoiceitems.tenantid = thecurrenttenantid order by invoicedate
Run Code Online (Sandbox Code Playgroud)

当前的模式

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

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

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

InvoiceItems(tenantid uniqueidentifier,invoiceitemid uniqueidentifier primarykey,invoiceid uniqueidentifier,lineitemorder int)外键(tenantid,invoiceid)索引(聚集在invoiceitemid上)

SqlAzure要求每个表都有一个聚簇索引,因此它当前只在primarykeyid上,因为这是默认值.现在,这是每个表的唯一索引.整个系统中的表中有各种外键,并且没有索引外键表字段.

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

所有sql select语句都以linq到entity语句中的tenantid开头.

invoiceitems.tenantid = thecurrenttenantid order by invoicedate
Run Code Online (Sandbox Code Playgroud)

一些sql select语句只有一个顺序 - 有些在引入子表时有一些其他连接条件值

invoiceitems.tenantid = thecurrenttenantid and invoice.invoiceid = invoiceitems.invoiceid order by invoicedate
Run Code Online (Sandbox Code Playgroud)

以下是一些想法(除此之外我们对其他人开放) - 哪一个最好,为什么

主要指标选项

加快访问租户的记录

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

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

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

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

外国主要指数期权

加快加入速度

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

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

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

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

SQL SELECT优化索引选项

要加速常用的查询,例如来自发票的选择字段,其中tenantid =按顺序排列的值

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

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

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

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

kni*_*hor 2

看来你已经考虑了很多。无论我或其他人说什么,唯一确定的方法就是亲自测量。在这种情况下,这不再是一个 SQL Azure 问题,而是一个一般的 SQL Server 查询优化问题。

对于您的情况,有一些提示可以帮助您入门。当您使用 LINQ 时,您无法直接访问在 SQL 中运行的实际查询。您可能认为您知道查询应该是什么样子,但根据您使用的 EF 版本,它可以就如何构建查询做出一些有趣的决定。要准确找出正在运行的查询,您需要使用 SQL Profiler 或扩展事件。SQL Profiler 不适用于 SQL Azure,因此您需要使用扩展事件或在本地服务器上的某个位置获取数据库的副本,然后运行指向本地的应用程序。导出数据层应用程序和 SQL Server Management Studio (SSMS) 中的相关导入对此非常有用。

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

不要试图在本地数据库上进行优化。SQL Azure 的性能概要与大多数本地 SQL 安装不同。

综上所述,如果所有查询始终包含租户 ID,那么是的,我希望将其作为聚集索引的第一部分包含在内,从而提高查询性能。对于所有其他指标,我不太确定,所以我会测量、测量、测量。另请记住,索引不是免费的,您创建的每一个索引都会影响您的写入性能以及数据库的大小,因此我不会发疯并为所有内容建立索引。

最后,不要担心为你的 PK 使用 guid,如果你的数据库变得足够大,你需要通过租户 ID 来联合它(你的结构看起来会很好地处理)IDENTITY 列不再成为一个选项。