2000字范文,分享全网优秀范文,学习好帮手!
2000字范文 > SQL和PL/SQL的性能优化之四---联结与子查询

SQL和PL/SQL的性能优化之四---联结与子查询

时间:2022-04-07 11:22:46

相关推荐

SQL和PL/SQL的性能优化之四---联结与子查询

1、联结类型

A、相等联结(equi-join)

B、非相等联结(theta)

C、交叉联结(cross join)--笛卡尔联结

D、外联结(outer joiin)--左、右、全联结

E、自联结(self join)

F、层级联结(hierarchical join)--特殊的自联结

G、反联结(anti join)

H、半联结(semi-join)

---联结方法

A、嵌套循环:ORACLE会就第一张表(外表)中发现的每一行记录对第二张表(内表)执行一次搜索

因为内表查找必须发生多次,故它必须非常高效,通常这意味着索引查找必须支持内表。如果没有对内表的索引,你可能要对外表中的每一条记录扫描内表一次,这就是声名狼藉的嵌套表扫描(nested table scan)。即使内表上有索引,如果必须访问内表的全部或大部分数据,嵌套循环的过程还是没有排序合并或散列联结高效

B、排序合并:ORACLE必须按照联结列的值对每张表(或结果集)进行排序。一旦排完序,就对两个集合的数据进行合并。

适用于需要访问表中大部分数据或内表没有索引访问可用的联结。散列联结一般比排序合并更加高效。然而合并排序联结可用于无法使用散列联结的地方(比如不等联结)。

C、散列联结:ORACLE对两张表中的一张构建散列表。散列表以某种与嵌套循环联结中使用索引类似的方法查找匹配的记录。

2、联结方法的选择

A、嵌套循环通常可以提供更快速的响应时间,而散列、排序合并提供更大的吞吐量。

B、被处理的记录的子集越大,散列、排序合并就可能越快

C、嵌套循环通常只在索引可用于联结时才有效

D、用于排序的内存与CPU:大的排序可能消耗大量的资源并可能减慢执行速度。排序合并包含两次排序,而嵌套循环通常不包含排序。散列联结则也需要内存来构建散列表。

E、散列联结或许可以从并行和针对分区的操作中获得更大的益处---虽然嵌套循环和排序合并也可以并行执行。

---------散列联结和排序合并联结对内存都很敏感。要达到最优性能,排序合并需要更多的内存,当它的操作不能完全在内存中完成时,性能会急剧下降。

----避免联结---降低开销

A、反范式化:在一张表中维护另一张表的反范式化数据(在数据中引入冗余以实现提升性能的目的)

B、索引聚簇:共享相同键值(簇键)的多张表的记录会被存储在相同的数据块中,并可以通过聚簇索引定位。(单个IO检索所有表中的记录)

C、物化视图:将物化视图和查询重写联合起来,可以用来避免联结

D、位图联结索引:对合适的查询,位图联结索引可以极大地降低联结开销。

3、联结顺序

一般而言,让优化器来选择联结顺序更可取,如果要手动,最好遵循如下经验准则:

3.1驱动表(联结顺序中的第一张表)应该是一张具有最高选择性并具有高效的where子句条件的表。

3.2 尽可能早地在联结顺序中将最终结果集中,不需要的记录排除出去。

3.3要联结涉及表的较少的结果集,如果有索引支持的话,尝试对每个后续的联结都使用嵌套循环联结。否则优先使用散列联结,而不是排序合并联结。

3.4确保嵌套循环联结使用的索引包含被联结表在where子句中的所有字段和联结字段。

4、星形联结

ORACLE处理星形联结的默认方法是查询所有维度表(products,times和customers等)来检索与where子句条件相关的外键值。然而使用全笛卡儿联结合并这些结果集,产生的外键被用于识别所需的事实表记录。如果事实表上对外键值有合适的索引,它们可以被用来优化最后一步。

--星形转化弊端:A、如果在维度表中匹配的记录数很多,笛卡儿集可能产生巨大的结果集

B、需要支持所有可能的维度键绷带合的联合索引;创建这个索引可能不实际

--排除方法:在星形转化中,基于开销的优化器将把原查询从表联结的方式转化成对事实表的查询,这个查询仅包含针对每个维度的查询。

--实现方式:要实现星形转化计划,需要将参数star_transformation_enabled设置为TRUE,我们可以使用alter system和altersession来设置它,或者如果我们只想它对当前查询生效,可以通过提示opt_param来设置它。

例:select /*+opt_param(star_transformation_enable','true') star_transformation */

from sales a join products p using(prod_id) join times usiong(time_id) join customers c using(cust_id)

where week_ending_day = '29-nov-';

注意:星形转化的性能并不比对事实表添加联合索引的方式得到的性能更好。然而,我们通常无法创建足够多的联合索引来支持所有可能的查询,而通过星形转化,我们仅需在每一个外键上加一个位图索引以支持where了句条件。

位图联结索引通过避免直接访问维度表,通常可以提供最佳的星形联结性能

位置索引有显著的锁开销,应只在低并发环境下使用位图索引,在那里锁竞争不是问题。

5、层级查询---局部爆炸式增长,特殊的自联结

表中的一个列指向同一张表的另一条记录的主键,而这条记录反过来又指向另一条记录,一直下去直到层级的顶端。

例; employee表中的manager_id列与employee_id列构成了这样的层级。manager_id列指向雇员经理的employee_id列。

select lpad('',level)||employee_id,first_name,manager_id

from hr.employees

connect by prior employee_id = manager_id--从下往下找

start with employee_id = 100;--100代表CEO

如果存在piror列(manager_id列)上的索上,ORACLE可以使用基于索引的访问路径。

当要构建层级的一个小的子集时,基于索引的方法更优。而在构建完整的层级时,全表扫描的方法会更佳。

在层级查询时,往往优化器无法做出正确的选择索引或全表扫描,因此,当知道是要构建完整层级时,有时你想强制使用全表扫描(通过使用FULL提示或存储提纲)。如果你要构建一个层级的子集,确保有索此来支持更高效的基于索引的执行计划。

6、子查询--通常被转化或联结操作,一般的联结优化原则都可使用(反联结除外--ORACLE对它们有唯一优化途径)

A、简单子查询

B、关联子查询:select * from employees a

where salary = (select min(salary) from employees b

where b.department-id = a.department_id);

C、反联结子查询:not in,not exists

select count(*) from google_customers

where (cust_first_name,cust_last_name)

not in(select cust_first_name,cust_last_name from microsoft_customers);

D、半联结子查询:where in或where exists子查询

它们被叫作半联结是因为即使在第二张表中有多条记录,它们也仅在第一张表中返回记录。

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。