1

如果我执行如下查询,我将在两个不同的列上搜索相同的 ID。我应该有这样的索引吗?或者我应该创建 2 个单独的索引,每列一个?

modelBuilder.Entity<Transfer>()
  .HasIndex(p => new { p.SenderId, p.ReceiverId });

询问:

var transfersCount = await _dbContext.Transfers
    .Where(p => p.ReceiverId == user.Id || p.SenderId == user.Id)
.CountAsync();

如果我有一个像下面这样的查询,我是否需要所有 4 列上的多列索引?

var transfersCount = await _dbContext.Transfers
.Where(p => (p.SenderId == user.Id || p.ReceiverId == user.Id) &&
      (!transferParams.Status.HasValue || p.TransferStatus == (TransferStatus)transferParams.Status) &&
      (!transferParams.Type.HasValue || p.TransferType == (TransferType)transferParams.Type))
.CountAsync();
4

2 回答 2

2

我推荐两个单列索引。

两个单列索引在此查询中将执行得更好,因为两个列都在一个完全有序的索引中。相比之下,在多列索引中,只有第一列在索引中是完全排序的。

如果您对发送方和接收方使用 AND 条件,那么您将受益于多列索引。多列索引非常适用于多列具有必须全部评估以构建结果集的条件语句的情况(例如, WHERE receiver = 1 AND sender = 2)。在 OR 条件下,将利用多列索引,就好像它是仅用于第一列的单列索引;第二列将没有索引。

于 2022-01-26T05:46:27.403 回答
1

索引设计的全部复杂性将远远超过一个 SO 答案来解释;可能有关于它的书籍,并且它将作为数据库管理员工作的合理比例

索引需要维护成本,因此您通常会努力尽可能少地为您提供最大的灵活性来完成您想做的事情。通常,索引将具有一些定义其键的列以及对表中具有这些键的行的引用。使用索引时,数据库引擎可以快速查找键,并发现需要读取哪些行。然后它将这些行作为辅助操作查找。索引还可以存储不属于查找键的表数据,因此您可能会发现自己创建的索引还跟踪行中的其他列,这样当数据库在索引中找到它正在查找的键时,它也会可以访问查询所需的行数据,然后不需要启动第二个查找操作来查找该行。如果查询需要表中的太多行,数据库可能决定完全不使用索引;有一些阈值,超过它直接从表中读取所有行并搜索它们而不是使用索引来查找需要读取哪些行的间接性更快

索引索引可以服务多个查询的列;顺序很重要。如果您总是按姓名查询一个人,有时也按年龄查询,但您从不单独按年龄查询,那么索引 (name,age) 比索引 (age,name) 更好。(name,age) 上的索引可以为 justWHERE name = ...WHERR name = ... and age = .... 如果在 where 子句中使用 OR 关键字,则可以将其视为完全需要自己索引的单独查询。实际上,数据库可能决定将“姓名或年龄”作为两个并行查询运行,并结合结果以删除重复项。如果您的应用程序需要稍后更改,而不是仅仅查询 (name), (name and age) 的组合,它现在经常查询 (name), (name and age), (name or age), (age), (年龄和身高),那么有两个索引可能是有意义的:(姓名,年龄)加上(年龄,身高)。数据库可以使用其中的部分或全部来为常见查询提供服务。请记住,使用索引的一部分只能从左到右工作。(name, age) 上的索引通常不会单独提供年龄查询。

如果您使用 SQLServer 和 SSMS,您可能会发现显示查询计划也会显示缺少索引建议,因此值得仔细考虑是否需要添加索引。部署到 Microsoft azure 的应用程序还会自动查看由于缺少索引而导致性能下降的常见查询,这可能会促使您查看正在运行的查询并了解如何扩展或重新排列现有或新索引以覆盖它; 正如首先指出的那样,这并不是真正的几行的单一 SO 答案可以让你准备好“总是这样做,它会很好” - 大规模运营的公司雇用的人的唯一任务是确保数据库运行良好,他们通常对开发人员抱怨很多,对实体框架之类的事情更多,因为 EF LINQ 查询是与正在运行的实际 SQL 断开连接的层并且可能不是获取数据的最佳方法。所有这些事情你都必须面对。

在这种特殊情况下,似乎 SenderId+TransferStatus+TransferType 上的索引和 ReceiverId+TransferStatus+TransferType 上的另一个索引可以帮助显示的两个查询,但我不会说“肯定这样做”而不采取整体观点该表包含的所有内容中,这些列中有多少不同的值以及它在应用程序上下文中的用途。如果 Sender/Receiver 是唯一的,则将更多列作为键添加到索引中可能没有意义。如果 TransferStatus 和 Type 发生变化,使得它们的某种组合有助于唯一地识别数百个特定行中的某个特定行,那么它可能是有意义的,但是如果这个查询每天只运行一次,而另一个每秒使用 10 次...... ' 太多变数和未知数,无法为所提出的问题提供具体答案;不要过早地优化 - 仅仅因为它们在某个地方的某些 where 子句中使用而对列进行索引会为时过早

于 2022-01-26T06:55:42.427 回答