针对未索引列的查询
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
时。
何时不使用索引
- 小型表: 对于行数很少的表,维护索引的开销可能不值得性能提升。
- 写入密集型表: 索引会减慢写入操作(
create
、update
、delete
),因为索引也需要更新。避免对频繁写入操作的模型过度索引。 - 不常访问的表: 如果一个表很少被访问,索引的好处可能不足以弥补其开销。
- 大数据量列: 对大数据量的列进行索引可能会导致更高的存储需求,并且可能无法提供显著的性能改进。
- 很少过滤的列: 如果一个表经常被访问但很少通过特定列进行过滤,那么在该列上创建索引可能没有益处。
警告
即使您对某一列建立了索引,数据库也可能不总是使用它。许多数据库管理系统,如 PostgreSQL 和 MySQL,都有一个查询优化器,它会评估多个执行计划,并选择其认为最高效的那个。在某些情况下,这可能涉及忽略现有索引,而选择它认为对该特定查询性能更好的不同执行计划。