全表扫描(Full Table Scan)就是数据库为了检索到我们查找的数据而逐行的去扫描表中的所有记录。很明显,全表扫描是一种非常慢的SQL查询。想象一下,对一张百万级的表进行全表扫描性能有多差!使用索引可以有效避免全表扫描。
让我们看一些会造成进行全表扫描的情况:
统计信息还没有更新
通常,数据库的统计信息要与表数据和索引数据保持一致。但是,因为一些原因导致表或索引的统计信息没有及时更新,结果就有可能造成全表扫描。这是因为大多数RDBMS(关系型数据库)的查询优化器会根据这些统计信息来计算是否应该使用索引。如果没有这些统计信息或统计信息不准确,RDBMS可能会错误的认为执行全表扫描比使用索引更高效。
没有WHRER子句
如果查询语句没有过滤结果集的WHRER子句,会执行全表扫描。
没有使用索引
有些情况,即使创建了索引还会执行全表扫描。
虽然查询语句有WHERE子句,但是WHERE子句中使用的列没有匹配索引的"领导列"(leading column),就会执行全表扫描。领导列又称最左列(leftmost column),见下一节“最左前缀匹配原则”。
即使WHERE子句中使用了索引的最左列,仍有可能执行全表扫描。这一般是由于WHRE子句中使用了“比较”操作,而阻止了数据库使用索引!下面列举几个会造成这种情况的例子:
-
使用不等于操作(!= 或 <>)。
例如: WHERE NAME <> 'Jesus'
因为索引只能用于查找表中有什么,而不能用于查找表中没有什么。
-
使用`NOT`操作符。
例如:WHERE NOT NAME 'Jesus' 。原因同上。
-
通配符出现在字符串比较的开始位置。
例如:WHERE NAME LIKE '%programmer%' 。
以哪个字母开始都不清楚,索引也无能为力了。
最左前缀匹配原则
对于多列的混合索引(composite index),只有符合最左前缀(leftmost prefix)的索引才能被查询优化器使用。比如,某个3列的混合索引(col1,col2,col3),只有下面三种情况可以使用到索引: (col1), (col1, col2),和 (col1, col2, col3)。
对于下面的查询语句:
SELECT * FROM tbl_name WHERE col1=val1;
SELECT * FROM tbl_name WHERE col1=val1 AND col2=val2;
SELECT * FROM tbl_name WHERE col2=val2;
SELECT * FROM tbl_name WHERE col2=val2 AND col3=val3;
只有前两个SELECT语句使用到了索引,第3个和第4个查询虽然使用了索引列,但是(col2)和(col2,col3)不是混合索引(col1, col2, col3)的最左前缀。
相关阅读: