执行计划操作符是SQL执行的基本单元,所有的SQL语句最终都是转换成一连串的操作符最后在数据库中执行,得到需要的结果,操作符也是读懂执行计划的基础。
单表查询相关的操作符含义
CSCN : 基础全表扫描(a),从头到尾,全部扫描
SSCN : 二级索引扫描(b), 从头到尾,全部扫描
SSEK : 二级索引范围扫描(b) ,通过键值精准定位到范围或者单值
CSEK : 聚簇索引范围扫描© , 通过键值精准定位到范围或者单值
BLKUP : 根据二级索引的ROWID 回原表中取出全部数据(b + a)
1)CSCN
SQL> CREATE TABLE T1(C1 INT,C2 INT);
操作已执行
已用时间: 2.313(毫秒). 执行号:807.
SQL> insert into t1 select level,level from dual connect by level < 10000;
影响行数 9999
已用时间: 2.849(毫秒). 执行号:808.
SQL> commit;
操作已执行
已用时间: 0.310(毫秒). 执行号:809.
SQL> select * from t1 where c1 = 5;
行号 C1 C2
---------- ----------- -----------
1 5 5
已用时间: 0.792(毫秒). 执行号:810.
查看执行计划
SQL> explain select * from t1 where c1 = 5;
1 #NSET2: [1, 249, 16]
2 #PRJT2: [1, 249, 16]; exp_num(3), is_atom(FALSE)
3 #SLCT2: [1, 249, 16]; T1.C1 = 5
4 #CSCN2: [1, 9999, 16]; INDEX33555446(T1)
此处是根据C1字段进行过滤,没有创建任何索引,从T1中取出数据只能走全表扫描CSCN
2)SSCN(相当于索引全扫描)
在C1字段上创建普通索引
SQL> create index i_test1 on t1(c1);
操作已执行
已用时间: 4.695(毫秒). 执行号:814.
查看执行计划
SQL> explain select c1 from t1;
1 #NSET2: [1, 9999, 12]
2 #PRJT2: [1, 9999, 12]; exp_num(2), is_atom(FALSE)
3 #SSCN: [1, 9999, 12]; I_TEST1(T1)
SQL> explain select c2 from t1;
1 #NSET2: [1, 9999, 12]
2 #PRJT2: [1, 9999, 12]; exp_num(2), is_atom(FALSE)
3 #CSCN2: [1, 9999, 12]; INDEX33555446(T1)
通常CSCN和SSCN的代价差不多,SSCN和CSCN的区别在于,SSCN扫描出来的数据是按索引列进行排序
3)SSEK(索引范围扫描)
SQL> explain select * from t1 where c1 = 5;
1 #NSET2: [0, 249, 16]
2 #PRJT2: [0, 249, 16]; exp_num(3), is_atom(FALSE)
3 #BLKUP2: [0, 249, 16]; I_TEST1(T1)
4 #SSEK2: [0, 249, 16]; scan_type(ASC), I_TEST1(T1), scan_range[5,5]
由于C1列存在普通索引,此时查询条件C1=5,因此优化器优先选择通过索引范围扫描将符合条件的记录进行筛选,操作符后面的描述scan_range[5,5],表示精准定位到5,多数情况下这样是比较有效率的。在SSEK上面出现了BLKUP操作符,由于I_TEST1上没有C2的数据,而查询需要SELECT *,索引需要通过查询条件找到rowid,再通过rowid回原表查找整行数据。
4)BLKUP(相当于Table Access By Index Rowid)
SQL> explain select c1 from t1 where c1 = 5;
1 #NSET2: [0, 249, 12]
2 #PRJT2: [0, 249, 12]; exp_num(2), is_atom(FALSE)
3 #SSEK2: [0, 249, 12]; scan_type(ASC), I_TEST1(T1), scan_range[5,5]
当查询字段只有C1时,优化器只需通过索引找出符合条件的记录,无需通过rowid进行反表操作
5)CSEK
同一张表的聚簇索引只允许存在一个,默认建表时,基表就是一个rowid聚簇索引,因此对rowid的精准定位应该会走CSEK
SQL> explain select c1 from t1 where rowid = 6;
1 #NSET2: [0, 1, 12]
2 #PRJT2: [0, 1, 12]; exp_num(2), is_atom(FALSE)
3 #CSEK2: [0, 1, 12]; scan_type(ASC), INDEX33555446(T1), scan_range[exp_cast(6),exp_cast(6)]
如果创建了一个自定义聚簇索引,ROWID这个聚簇索引就不存在了,自定义聚簇索引将会取代ROWID聚簇索引
SQL> create cluster index i_index2 on t1(c2);
操作已执行
已用时间: 38.936(毫秒). 执行号:815.
SQL> explain select c1 from t1 where rowid = 6;
1 #NSET2: [1, 249, 12]
2 #PRJT2: [1, 249, 12]; exp_num(1), is_atom(FALSE)
3 #SLCT2: [1, 249, 12]; T1.ROWID = var1
4 #CSCN2: [1, 9999, 12]; I_INDEX2(T1)
SQL> explain select c1 from t1 where c2 = 6;
1 #NSET2: [0, 249, 8]
2 #PRJT2: [0, 249, 8]; exp_num(1), is_atom(FALSE)
3 #CSEK2: [0, 249, 8]; scan_type(ASC), I_INDEX2(T1), scan_range[6,6]
此时对ROWID的精准定位不再走CSEK,而是CSCN全表扫描,对C2字段的精准过滤走CSEK