SQL中的表扫描和索引扫描

时间:2012-01-02 16:06:11

标签: sql database-table

SQL中的表扫描和索引扫描之间的区别是什么?具体使用它?

4 个答案:

答案 0 :(得分:13)

表扫描意味着遍历所有表行。

索引扫描意味着迭代所有索引项,当项索引满足搜索条件时,通过索引重新检索表行。

Usualy索引扫描比表扫描更便宜,因为索引比表更平坦。

他们对这个问题有很多参考书目。样品:

  

索引访问是SQL Server使用现有的访问方法   用于读写数据页的索引。因为索引访问显着   减少了I / O读取操作的数量,它通常优于a   表扫描。

  

在此方法中,通过遍历索引来检索行,使用   语句指定的索引列值。索引扫描   根据一列或多列的值从索引中检索数据   在索引中。要执行索引扫描,Oracle会搜索索引   语句访问的索引列值。如果声明   只访问索引的列,然后Oracle读取索引   列值直接来自索引,而不是来自表。

答案 1 :(得分:11)

大多数查询引擎都有一个查询优化器,它试图生成有效的查询执行策略。如果索引可用,这可以使查询更快,那么查询优化器将执行索引扫描或索引搜索,否则执行表扫描。

示例:

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;

这里还有另一种选择。在这种情况下,索引搜索可能不会比表扫描更快,但是,因为我们只检索catergory_id,所以索引扫描(而不是索引搜索)可能更快。索引扫描读取索引表的每个条目,而不是利用树结构(索引查找的内容)。但是,由于请求的信息完全包含在索引中,因此不需要访问数据表。索引扫描就像表扫描O(n)操作一样,但由于索引通常小于表,因此扫描索引比扫描表需要更少的磁盘访问。

整个问题非常复杂,很大程度上取决于数据库引擎。如果您想了解更多信息,请阅读db供应商提供的文档。

答案 2 :(得分:2)

由于@danihp回答了问题的第一部分,我将尝试回答第二个“它在哪里使用”。这适用于Oracle,但大多数RDBMS都适用。

假设我们有一个表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 where条件匹配的所有值,即索引扫描。我们再一次选择不在索引中的列,因此我们必须重新输入表来获取它们。

最后,如果我们的查询是select id from my_table where another_column = 'yes'。我们在another_column上没有索引,因此我们必须执行表扫描来查找值,即我们必须找到表where another_column = 'yes'中的所有内容。

现在,在这些实例中,表扫描和索引扫描之间似乎没有太大区别。我们仍然需要在数据库中的对象中找到一个值。但是,由于索引要小得多并且专门设计用于扫描(参见其他答案),如果您只想要一小部分行,那么进行索引扫描通常要快得多表格。如果你想说10%的表,那么这一点就变成了“它取决于”。

答案 3 :(得分:2)

至少对于SQL Server:

索引扫描可以更快,因为可能是索引不覆盖表中的整个列集,而表(或聚簇索引)扫描必须读取所有数据。如果索引确实包含表中的所有列,那么它应该大致相当于表扫描,并且索引扫描和表(或CIX)扫描之间的选择将是抛硬币。不同之处在于,当索引中的列数较少时,您可以在8kb页面上容纳更多索引行,从而导致您为了扫描索引中的所有数据而必须读取的整个页面更少。

为了说明我的意思,想象一下,如果您有两份电话簿,一份是姓氏,名字,街道地址和电话号码,另一份是姓氏,名字和电话号码。现在想象一下,因为街道地址不需要打印,所以您可以在电话簿的任何页面上添加两列额外的姓名和电话号码。最终的结果是电话簿更薄,因为您可以在更少的页面上容纳相同数量的电话号码。接下来,假设您负责计算书中的电话号码数量。您会选择哪一个,列出街道地址的页面(具有更多页面,类似于表扫描)或没有街道地址的页面(页面数量较少,类似于大多数索引扫描)?我会选择页数较少的那个。

另一个问题是可以过滤一些索引,这意味着它们不仅在大多数情况下具有更少的列(因此可以在单个页面上容纳更多行),但它们也可以具有消除的WHERE子句很多行。在这种情况下,索引扫描也会比表扫描更好(但这只适用于具有匹配的WHERE子句和相同语义的查询)。