跳至主要内容

未索引列上的查询

Optimize 提供推荐以帮助您识别和解决由缺少数据库索引引起的性能问题。

以下针对 User 模型的查询使用 where 属性 在没有索引的列上进行过滤。

await prisma.user.findFirst({
where: {
name: "Marc"
}
})

await prisma.user.findFirst({
where: {
name: "Jon"
}
})

await prisma.user.count({
where: {
name: "Nikolas"
}
})

问题是什么?

索引允许数据库更快地检索数据,类似于书中的索引如何帮助您在不阅读每一页的情况下找到信息。

当使用 Prisma 和 where 属性时,如果未为相关列定义索引,数据库可能需要扫描表中的每一行(“表全扫描”)以查找匹配项。这可能由于以下几个原因而不可取。

用户体验

对于大型数据集,如果数据库必须扫描整个表以查找匹配行,用户将体验到更长的等待时间。

资源利用

  • 高 CPU 使用率:扫描大型表会显着增加 CPU 使用率,降低整体系统性能。
  • 内存消耗:表全扫描需要更多内存来处理和存储数据。
  • 磁盘 I/O:表全扫描会增加磁盘输入/输出操作,可能会减慢其他数据库活动。
警告

虽然这些问题在开发中由于数据集较小而可能不会出现,但在生产环境中,数据集通常要大得多,它们可能会成为严重问题。

更多关于数据库索引

索引的工作原理

索引创建一种数据结构,它存储索引列的值以及指向表中对应行的指针。当您使用索引列查询数据库时,数据库可以使用此索引快速找到相关行,而不是扫描整个表。

索引的权衡

  • 空间与时间:索引需要额外的存储空间来保存索引数据,但它显着加快了数据检索速度。
  • 更新开销:每次向表中添加、更新或删除数据时,都会有开销来保持索引最新,这会减慢写操作的速度。

何时使用索引

  • 大型数据集:索引对于具有大量行的表特别有用。
  • 使用过滤或排序的频繁查询:对经常用于 过滤或排序 的列使用索引。
  • 查找相关数据:对外键列使用索引,以加快检索相关记录的速度,例如在使用 include 时。

何时不使用索引

  • 小型表:对于行数很少的表,维护索引的开销可能不值得性能提升。
  • 写入密集型表:索引会减慢写入操作(createupdatedelete)的速度,因为索引也需要更新。避免在频繁执行写入操作的模型上进行过度索引。
  • 很少访问的表:如果表很少访问,索引的优势可能无法证明开销合理。
  • 具有大型数据的列:索引具有大型数据的列会导致更高的存储要求,并且可能不会提供显着的性能改进。
  • 很少过滤的列:如果表经常访问但很少按特定列进行过滤,则在该列上创建索引可能没有益处。
警告

即使您索引了一个列,数据库也可能不会总是使用它。许多数据库管理系统,如 PostgreSQL 和 MySQL,都有一个查询优化器,它会评估多个执行计划并选择它估计最有效的计划。在某些情况下,这可能涉及忽略现有索引,而支持它确定将为该特定查询执行更好的其他执行计划。