数据库SQL执行的效率会直接影响整体应用的性能,在大数据量和复杂SQL语句的情况下,一定要查看数据库SQL的执行计划,并分析哪些语句耗费较多,值得优化!就Oracle数据库而言,下面潘老师来谈谈我们该如何去查询和分析执行计划?
执行计划(explainplan)是指:一条查询语句在数据库中的执行过程或访问路径的描述。
2、执行顺序在plsql中我们可以使用图中的箭头直接来调试执行顺序,非常方便,像Navicat没有就可以根据据Operation缩进来判断,缩进最多的最先执行(当缩进相同时,最上面的最先执行),同一级如果某个动作没有子ID就最先执行,同一级的动作执行时遵循最上最右先执行的原则。
3、一些动作的解释如plsql那张图中类似INDEXRANGESCAN、TABLEACCESSFULL等等,即描述的是该动作执行时表访问(或者说Oracle访问数据)的方式;
TABLEACCESSFULL:全表扫描TABLEACCESSBYROWID:通过ROWID的表存取TABLEACCESSBYINDEXSCAN:索引扫描
1)全表扫描:Oracle会读取表中所有的行,并检查每一行是否满足SQL语句中的Where限制条件;全表扫描时可以使用多块读(即一次I/O读取多块数据块)操作,提升吞吐量;使用建议:数据量太大的表不建议使用全表扫描,除非本身需要取出的数据较多,占到表数据总量的5%~10%或以上。
2)通过ROWID的表存取ROWID是由Oracle自动加在表中每行最后的一列伪列,既然是伪列,就说明表中并不会物理存储ROWID的值,你可以像使用其它列一样使用它,只是不能对该列的值进行增、删、改操作,一旦一行数据插入后,则其对应的ROWID在该行的生命周期内是唯一的,即使发生行迁移,该行的ROWID值也不变。
让我们再回到TABLEACCESSBYROWID来:行的ROWID指出了该行所在的数据文件、数据块以及行在该块中的位置,所以通过ROWID可以快速定位到目标数据上,这也是Oracle中存取单行数据最快的方法;
3)索引扫描在索引块中,既存储每个索引的键值,也存储具有该键值的行的ROWID。扫描其实分为两步:Ⅰ:扫描索引得到对应的ROWIDⅡ:通过ROWID定位到具体的行读取数据
INDEXUNIQUESCAN:索引唯一扫描INDEXRANGESCAN:索引范围扫描INDEXFULLSCAN:索引全扫描INDEXFASTFULLSCAN:索引快速扫描INDEXSKIPSCAN:索引跳跃扫描
a)INDEXUNIQUESCAN(索引唯一扫描):
针对唯一性索引(UNIQUEINDEX)的扫描,每次至多只返回一条记录;表中某字段存在UNIQUE、PRIMARYKEY约束时,Oracle常实现唯一性扫描;
b)INDEXRANGESCAN(索引范围扫描):
使用一个索引存取多行数据;发生索引范围扫描的三种情况:
在唯一索引列上使用了范围操作符(如:><<>>=<=between)在组合索引上,只使用部分列进行查询(查询时必须包含前导列,否则会走全表扫描)对非唯一索引列上进行的任何查询[/list]c)INDEXFULLSCAN(索引全扫描):进行全索引扫描时,查询出的数据都必须从索引中可以直接得到(注意全索引扫描只有在CBO模式下才有效)d)INDEXFASTFULLSCAN(索引快速扫描):扫描索引中的所有的数据块,与INDEXFULLSCAN类似,但是一个显著的区别是它不对查询出的数据进行排序(即数据不是以排序顺序被返回)e)INDEXSKIPSCAN(索引跳跃扫描):Oracle9i后提供,有时候复合索引的前导列(索引包含的第一列)没有在查询语句中出现,oralce也会使用该复合索引,这时候就使用的INDEXSKIPSCAN;
当然还有一些表连接方式的动态在此就不再展开了,我们在优化SQL时重要的一步就是尽量避免了全表扫描,查看SQL是否命中索引,优化COST较大的执行步骤!