使用索引和表演表扫描是访问数据库中数据的两种基本方法,每个方法都取决于情况。
数据库中的索引是一个数据结构,可以通过允许系统快速定位行而无需扫描表中的每一行来实现更快的查找。大多数关系数据库都使用B+树结构作为索引,该索引以树形式组织钥匙和指针。这允许在对数时间复杂度中搜索,插入和删除$$ o(\ log n)$$,通常比用$$ o(n)$$扫描整个桌子的速度要快得多。索引可以被聚类或非聚类,并带有群集索引以物理排序的顺序存储数据,从而以数据修改的额外开销成本来改善范围扫描性能。索引也可以是复合,部分,过滤或基于哈希的,并根据特定的查询模式调整。
相比之下,无论查询的选择性如何,表扫描(或完整表扫描)都会依次读取表中的每一行。这涉及扫描表的所有数据块,通常被认为是最昂贵的访问方法,因为它处理的数据超过了必要的数据。但是,在某些情况下,表扫描可以表现良好。例如,当查询检索一大比例的行时,使用索引的开销(通常需要对实际行需要额外查找)超出一次扫描整个桌子的成本。表扫描可以利用多块读数,从而可以读取大量数据,而I/O操作较少,因此与读取索引扫描随机需要的许多单独块相比,延迟延迟。
一个主要的权衡涉及查询返回的数据集的选择性和大小。如果查询过滤到少量行(高选择性),则索引通常要优于表格扫描,因为它们只需要访问相关数据即可。但是,随着行返回的百分比增加,索引扫描的成本可能会增加,因为可能需要多个关键查找,并且数据库引擎必须执行其他随机I/O操作。在某个阈值下,通常约占表行的10-20%,但取决于数据宽度和硬件,全表扫描变得更加有效。这是因为无论选择性如何,扫描成本保持恒定,只需顺序依次读取表即可。
当覆盖的列比完整的表行还要少或更紧凑时,索引扫描通常比表扫描少于表扫描。例如,索引可能仅包括没有完整表行数据的索引列,使其更薄,并允许更多的行适合每个数据库页面。与扫描整个表数据相比,扫描索引时,这会减少I/O高架。此外,可以对某些索引进行过滤(部分索引),以排除无关的行,从而进一步降低了扫描足迹。
另一方面,全桌扫描在数据库维护方面少写负担。索引在数据修改操作(例如插入,更新和删除)期间引入开销。表的每个更改都需要更新索引,有时会导致写入延迟和存储开销增加,尤其是在表上存在许多索引的情况下。该开销也会影响并发性,并导致在沉重的写作环境中引起争议。因此,表扫描只需以自然顺序读取数据,而无需额外的结构维护,避免了此费用。
另一个重要的考虑因素是缓存和硬件特征的效果。表扫描受益于顺序I/O和预摘要,从而使系统可以有效地读取多个连续块,通常是从内存中读取的。相反,索引扫描会产生随机I/O以获取不同的数据块,尤其是如果索引扫描必须将行指针查找到堆存储中时。这可以使索引扫描在磁盘随机I/O性能较慢的系统上较慢,尽管SSD和大型内存池缩小了此间隙。这种情况还取决于数据库引擎的并行性和多线程功能等细节,在该范围内并行表扫描可以显着增强吞吐量。
此外,内部分裂和物理存储布局会影响性能权衡。堆放堆的桌子上的表扫描可能会遭受转发记录的困扰,由于更新,行已移至不同的页面,从而恶化了扫描效率。群集的索引存储了按键排序的数据,可以避免此问题,有时会制作“表扫描”等效于群集索引扫描。但是,好处是在大量数据流失期间昂贵的行重新排序的成本。
从查询优化器的角度来看,索引扫描与表扫描之间的决策通常由基于成本的估计模型做出,考虑到数据分布,行计数和硬件成本的统计信息。优化器平衡了CPU,I/O和内存成本,以选择最有效的访问路径。这些决定可能会受到可用内存,缓存状态和查询模式等因素的影响。何时使用一个或另一个之间没有固定的阈值;每个系统和工作负载的跨界点变化。
总之,使用索引和表扫描之间的权衡包括:
- 性能与数据量:过滤到几行时索引跑赢大盘;表扫描可以更好地用于大型数据检索。
- I/O模式:索引扫描会导致随机I/O读取;表扫描受益于顺序I/O和多块读取。
- 维护开销:由于索引结构的更新,索引增加了写操作成本;桌子扫描不会引起这一点。
- 存储效率:索引可以通过覆盖较少的列来紧凑;表扫描处理完整的行,并有更多数据。
- 缓存效果:表扫描可以有效地利用数据缓存,尤其是在大量顺序读取的情况下;由于随机访问,索引扫描可能不会受益那么多。
- 优化器决策:基于成本的查询优化器根据查询统计和工作负载细节在这些选项之间动态选择。
- 数据布局的影响:堆表可能会在扫描过程中受到罚款;聚类索引在物理上组织数据,但增加了更新成本。