连接(Join)方法
连接是指从一个或者多个表中检索数据。Oracle主要有3种连接方法:嵌套循环连接(Nested Loop Joins)、哈希连接(Hash Joins)和排序合并连接(Sort Merge Joins)。在SELECT语句中,连接方法至关重要,它直接影响查询的性能。
嵌套循环连接(Nested Loop Joins)
嵌套循环连接适合处理小量数据。Oracle首先选择一张表作为连接的驱动表(Driving Table),这张表也被叫做外部表(Outer Table),其他表被当做内部表(Inner Table),内部表也叫被驱动表。对于驱动表中的每行,Oracle将访问内部表中的所有行。
嵌套循环连接可以快速返回查询结果的前几行,这是因为,它不需要等到全部循环结束再返回结果集,而是不断地返回查询的结果,也就是语句边执行边返回结果。
哈希连接(Hash Joins)
哈希连接用于处理大数据量的数据集(特别是一个大表和一个小表的连接)。Oracle从两个表中选择一个较小的表,按照连接关键字(Join Key),在内存中建立哈希表(因此哈希表中较小的表适合放在内存中),然后,Oracle扫描另外一个表(大表),从中发现可以被连接的行。
排序合并连接(Sort Merge Joins)
排序合并连接的原理是,两个表先按照连接关键字(JoinKey)进行排序,再把排好序的两个结果集合并在一起。所以,如果其中一个结果集已经排好序,"排序合并连接"方式的速度将比"哈希连接"方式快。
4.统计信息的解释
通过AUTOTRACE,我们不仅可以获得SQL语句的执行计划,还可以获得SQL语句的统计信息。接下来,我们将对SQL语句的统计信息进行解释。
0 recursive calls--递归调用的次数。
0 db block gets--当前块(Current Block)被请求的次数,当前块是指未被修改过的块。
32 consistent gets--对块一致性读的请求次数,一致性读涉及读回滚段。
0 physical reads--从磁盘读的块的数量。
0 redo size--产生的回滚数据的大小,单位是字节(Bytes)。
7748 bytes sent via SQL*Net toclient--后台进程发送给客户端的信息量大小,单位是字节。
603 bytes received via SQL*NetFROM client--客服端发给数据库服务器的信息量的大小,单位是字节。
19 SQL*Net roundtrips to/FROMclient--Oracle Net发送和接受的信息数量,单位是条。
0 sorts (memory)--内存排序的次数。
0 sorts (disk)--磁盘排序的次数。
256 rows processed--处理数据的行数(通常指返回的记录数)。
5.SQL优化的目标
有的朋友说,减少一条SQL语句的执行时间是我们优化SQL语句的目标。对,没错,但是在大部分情况下,我们不能在生产系统中直接执行调试中的SQL语句,以获得该语句的执行时间。不过,在不真正执行SQL语句的情况下,我们有一些衡量指标,这些指标可以帮助我们衡量优化后的SQL语句是否真的比以前的SQL语句更加高效。因此,根据经验,笔者总结SQL调整的目标是:
减小consistent gets的值
减小db block gets的值
减少排序,尤其磁盘排序sorts(disk)
减少递归调用(recursive calls)
减小执行代价(cost)
要实现SQL调整的目标,我们需要采取诸如加索引、改写SQL语句等措施。
知识点索引--执行代价
执行代价与SQL语句使用的资源(I/O、CPU、内存等)有关。如果一条SQL语句使用的资源较多,我们就说该SQL语句的执行代价大。执行代价的大小是衡量SQL语句是否高效的标准之一,但是,执行代价是一个相对值。
6.SQL优化措施(基本准则)
本节将介绍SQL语句优化的措施。SQL语句的优化是一个复杂而循序渐进的过程。在对SQL语句实行优化措施之后,我们要查看衡量SQL语句的各项指标是否下降。有的优化措施不仅不能加速SQL语句的执行,反而使SQL语句的执行更加缓慢。进行SQL优化时,我们可以采取下面的措施:
收集统计信息
重构索引
重构数据
禁用约束和触发器
尽量使用相同的SQL语句
改写SQL语句
收集统计信息
统计信息是存放在数据字典中的一系列的数据,它用于精准地描述数据库和数据库中的对象(如表、索引)。统计信息包括:表的统计信息、列的统计信息、索引的统计信息、系统的统计信息(包括CPU和I/O的)。统计信息能够帮助优化器选择最好的执行计划,所以,统计信息的精确性尤为重要。如果你没有收集统计信息或者很长时间没有重新收集统计信息(旧的统计信息不能准确地反映数据变化),都将影响优化器选择最优的执行计划。
因为数据库中的对象和数据在不断变化,所以我们应该定期收集统计信息。有以下两种方法收集统计信息。
自动收集统计信息
在默认情况下,Oracle启动了统计信息的自动收集功能,如果你禁用了统计信息的自动收集,可以使用下面的命令启用统计信息的自动收集。
1.BEGIN
2.DBMS_AUTO_TASK_ADMIN.ENABLE(
3.client_name=>'autooptimizerstatscollection',
4.operation=>NULL,
5.window_name=>NULL);
6.END;
自动收集统计信息会消耗一部分系统资源,如果没有必要可以关闭该功能。关闭自动收集统计信息的命令如下所示:
1.BEGIN
2.DBMS_AUTO_TASK_ADMIN.DISABLE(
3.client_name=>'autooptimizerstatscollection',
4.operation=>NULL,
5.window_name=>NULL);
6.END;
手动收集统计信息
如果我们不想启用"自动收集统计信息",可以利用包DBMS_STATS来手工收集统计信息。包DBMS_STATS包含如下的过程:
收集索引的统计信息
1.EXECUTEDBMS_STATS.GATHER_INDEX_STATS('ITME','KK');
上述命令收集用户模式itme下的索引kk。
收集表的统计信息
1.EXECUTEDBMS_STATS.GATHER_TABLE_STATS('ITME','STUDENTBOOK');
上述命令收集用户itme的表studentbook的统计信息。
收集用户拥有的所有对象的统计信息
1.EXECUTEDBMS_STATS.GATHER_SCHEMA_STATS('ITME');
上述命令收集用户itme拥有的所有对象的统计信息。
收集数据字典对象的统计信息
1.EXECUTEDBMS_STATS.GATHER_DICTIONARY_STATS;
收集数据库中所有对象的统计信息
1.EXECUTEDBMS_STATS.GATHER_DATABASE_STATS;
重构索引
重构索引的工作包括以下几方面:
删除多余的索引,以加速DML语句的执行。如果一个表上的操作是以DML为主,考虑删除冗余的DML。
删除组成索引列中无用的列。因为有的列在WHERE条件中很少使用或者从未使用,这样的列不仅不利于查询,可能会反而阻碍DML语句的执行。
改变索引中列的顺序,使索引中列的顺序和WHERE条件中列的顺序相同。
考虑往索引中添加新的列。
重建索引,消除索引中的碎片。
注意:索引不是灵丹妙药。有时候索引却会加重系统的负担。
重构数据
如果数据分布不合理,即使我们再怎么调整SQL语句,效果也只是杯水车薪。数据的分布是否合理将直接影响SQL的性能。在此,我们主要讨论数据分布的两项技术。
数据分布的其中一项技术是分区(Partitioning),理想的分区技术是,将一个大表按照一定的逻辑分成n块,每块单独存放在一个物理磁盘中,这时候需要n块磁盘,并在分区表上创建相应的索引。
数据分布的另外一项技术是聚簇(Cluster)。如果两个表经常按照某列进行连接(Join),则可以把这两个表放到聚簇中。这项技术使两个表中的数据物理地存放在一起,减少I/O,加速对两个表的访问。