跳到主要内容

非索引列上的查询

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:全表扫描会增加磁盘输入/输出操作,可能减慢其他数据库活动。
警告

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

关于数据库索引的更多信息

索引如何工作

索引会创建一个数据结构,用于存储索引列的值以及指向表中相应行的指针。当您使用索引列查询数据库时,数据库可以使用此索引快速定位相关行,而无需扫描整个表。

索引的权衡

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

何时使用索引

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

何时不使用索引

  • 小型表:对于行数非常少的表,维护索引的开销可能不值得性能上的提升。
  • 写入繁重的表:索引会减慢写入操作(create, update, delete),因为索引也需要更新。避免在写入操作频繁的模型上过度索引。
  • 不常访问的表:如果一个表很少被访问,索引的好处可能不足以抵消开销。
  • 包含大数据量的列:索引包含大数据量的列可能会导致更高的存储要求,并且可能无法带来显著的性能提升。
  • 很少用于过滤的列:如果一个表经常被访问,但很少按特定列进行过滤,那么在该列上创建索引可能没有好处。
警告

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