在SQL中,表扫描和索引扫描有什么区别,它们在哪些特定场景下使用?
在SQL中,表扫描和索引扫描有什么区别,它们在哪些特定场景下使用?
表扫描是迭代所有表行。
索引扫描是迭代所有索引项,当索引项满足搜索条件时,通过索引检索表行。
通常情况下,索引扫描比表扫描更节省成本,因为索引比表更扁平。
有很多关于这个问题的文献。例如:
索引访问是一种访问方法,在此方法中,SQL Server使用现有的索引读取和写入数据页面。由于索引访问大大减少了I/O读操作的数量,因此它通常优于表扫描。
在这种方法中,通过遍历索引并使用语句指定的索引列值来检索行。索引扫描基于索引中一个或多个列的值从索引中检索数据。要执行索引扫描,Oracle会根据语句访问的索引列值搜索索引。如果语句仅访问索引的列,则Oracle会直接从索引中读取索引列值,而不是从表中读取。
SELECT * FROM tbl WHERE category_id = 5;
如果 category_id 没有索引,将执行表扫描,即将检查表中每个记录以找到正确的 category_id。
然而,如果 category_id 被索引,情况会变得更加复杂。如果表非常大,则可能选择索引搜索。但是,如果表很小,则优化器可能仍然决定表扫描更快,因为需要访问索引的一些开销。如果 category_id 不够具有选择性,例如只有两个类别,则对于大表来说,扫描表可能更快。
索引通常是以树结构组织的。在树中查找项是一个 O(log n) 操作,而表扫描是一个 O(n) 操作。速度主要由执行查询所需的磁盘访问次数确定。对于小表,先查找索引,然后访问查找到的条目可以生成更多的磁盘访问。
让我们再看另一个查询:
SELECT category_id FROM tbl WHERE category_id BETWEEN 10 AND 100;
还有另一种选择可供使用。在这种情况下,索引扫描可能不比表扫描快,但由于我们只检索category_id,因此索引扫描(而不是索引查找)可能更快。索引扫描读取索引表的每个条目,而不是利用树结构(索引查找所做的)。然而,由于所请求的信息完全包含在索引中,因此不需要访问数据表。索引扫描和表扫描都是O(n)操作,但由于索引通常比表小,因此扫描索引所需的磁盘访问次数比扫描表少。
整个问题非常复杂,非常依赖于数据库引擎。如果想了解更多,请阅读db供应商提供的文档。
my_table
,它在列id
上具有唯一索引,并且在列yet_another_column
上具有第二个非唯一索引:create my_table ( id varchar2(20) not null
, another_column not null
, yet_another_column
, constraint pk_my_table primary key (id)
);
create index i_my_table on my_table ( yet_another_column );
select * from my_table where id = '1'
,这将/应该对索引pk_my_table
进行唯一索引扫描。然后我们使用索引重新进入表格,返回my_table
中所有id ='1'
的内容。select id from my_table where id = 'a'
,则没有必要进行第二阶段,因为我们需要的所有值都包含在索引中。在这种情况下,查询仅会进行唯一索引扫描。select * from my_table where yet_another_column = 'y'
,那么我们在列上有一个索引,但它不是唯一的,因此我们必须浏览整个索引以尝试找到与我们的where条件匹配的所有值,即索引扫描。再次选择了不在我们的索引中的列,因此我们必须重新进入表格以获取它们。select id from my_table where another_column = 'yes'
。我们在another_column
上没有索引,因此我们必须进行表扫描以查找该值,即我们必须在表格中查找where another_column = 'yes'
的所有内容。