指定全局表提示
指定表的提示通常是指发生提示的DELETE,SELECT或UPDATE查询块中的表,而不是指语句引用的任何视图中的表。 如果要为显示在视图中的表指定提示,Oracle建议使用全局提示,而不是在视图中嵌入提示。 您可以使用包含具有表名的视图名称的扩展tablespec语法,将本章中描述的表提示转换为全局提示。
此外,可选的查询块名称可以在tablespec语法之前。 请参见“在提示中指定查询块”。
指定表的提示使用以下语法,其中view指定视图名称,table指定表的名称或别名:
如果指定了视图路径,则数据库将从左向右解析提示,其中第一个视图必须存在于FROM子句中,并且必须在前一视图的FROM子句中指定每个后续视图。
例3创建了一个视图v,用于返回员工的姓名,他或她的第一份工作,以及该员工在其所在部门工资最高的每位员工的所有直接报告的总工资。 在查询数据时,您希望在视图e2中强制使用索引emp_job_ix作为表e3。
示例3使用全局提示示例
CREATE OR REPLACE VIEW v ASSELECT e1.first_name, e1.last_name, j.job_id, sum(e2.salary) total_salFROM employees e1, ( SELECT * FROM employees e3) e2, job_history jWHERE e1.employee_id = e2.manager_idAND e1.employee_id = j.employee_idAND e1.hire_date = j.start_dateAND e1.salary = ( SELECT max(e2.salary) FROM employees e2WHERE e2.department_id = e1.department_id )GROUP BY e1.first_name, e1.last_name, j.job_idORDER BY total_sal;
通过使用全局提示结构,您可以避免使用视图主体e2中的索引提示的规范来修改视图v。 要强制使用表e3的索引emp_job_ix,可以使用以下语句之一:
SELECT /*+ INDEX(v.e2.e3 emp_job_ix) */ * FROM v;SELECT /*+ INDEX(@SEL$2 e2.e3 emp_job_ix) */ * FROM v;SELECT /*+ INDEX(@SEL$3 e3 emp_job_ix) */ * FROM v;
注意:
Oracle数据库忽略引用多个查询块的全局提示。 例如,在以下查询中忽略LEADING提示,因为它使用点表示法来包含表a和查询查询块v的主查询块:
SELECT /*+ LEADING(v.b a v.c) */ *FROM a, vWHERE a.id = v.id;
为避免此问题,Oracle建议您使用@SEL表示法在提示中指定查询块:
SELECT /*+ LEADING(A@SEL$1 B@SEL$2 C@SEL$2) */FROM a a, v vWHERE a.id = v.id;
---------------------------------------------------------------------------------------------------------------------------------
Example 4 Using Global Hints with NO_MERGE
The global hint syntax also applies to unmergeable views as in Example 19–4.
CREATE OR REPLACE VIEW v1 ASSELECT *FROM employeesWHERE employee_id < 150;CREATE OR REPLACE VIEW v2 ASSELECT v1.employee_id employee_id, departments.department_id department_idFROM v1, departmentsWHERE v1.department_id = departments.department_id;SELECT /*+ NO_MERGE(v2) INDEX(v2.v1.employees emp_emp_id_pk)FULL(v2.departments) */ *FROM v2WHERE department_id = 30;
提示导致v2不合并,并为employee和department表指定访问路径提示。 这些提示被下推到(非合并)视图v2中。
指定复杂的索引提示
指定索引的提示可以使用简单索引名称或带括号的列列表,如下所示:
语义如下:
■table指定名称
■column指定指定表中列的名称
- 列可以选择以表限定符作为前缀,允许提示指定位图连接索引,其中索引列与索引表位于不同的表上。如果存在表限定符,则它们必须是基表,而不是查询中的别名。
- 索引规范中的每个列必须是指定表中的基本列,而不是表达式。除非索引规范中指定的列形成基于函数的索引的前缀,否则不能使用列规范提示基于函数的索引。
■index指定索引名称
当tablespec在提示规范中后跟indexspec时,允许使用逗号分隔表名和索引名,但不是必需的。也允许逗号(但不是必需的)分隔多次出现的indexspec。
提示解析如下:
■如果指定了索引名称,则数据库仅考虑指定的索引。
■如果指定了列列表,并且存在其列与数字和顺序中的指定列匹配的索引,则数据库仅考虑此索引。如果不存在此类索引,则会考虑表中具有指定列作为指定顺序的前缀的任何索引。在任何一种情况下,行为都与用户在所有匹配索引上单独指定相同提示完全相同。
例如,在示例3中,job_history表在employee_id列上具有单列索引,在employee_id和start_date列上具有连接索引。要专门指示优化器使用索引,可以按如下方式提示查询:
SELECT /*+ INDEX(v.j jhist_employee_ix (employee_id start_date)) */ * FROM v;
使用视图提示
Oracle不鼓励在视图(或子查询)内部或视图(或子查询)上提示,因为您可以在一个上下文中定义视图并在另一个上下文中使用它们。此外,此类提示可能会导致意外的执行计划。特别是,视图内部或视图上的提示处理方式不同,具体取决于视图是否可合并到顶级查询中。
要为视图或子查询中的表指定提示,最好使用全局提示语法。请参见“指定全局表提示”。
如果您决定使用带有视图的提示,则以下部分将描述该行为。
提示和复杂视图
默认情况下,提示不会在复杂视图中传播。例如,如果在查询中指定一个提示来选择复杂视图,则不会遵循此提示,因为它不会被推入视图中。
除非提示位于基本视图中,否则它们可能不会受到针对视图的查询的影响。
提示和可合并的视图
可合并视图是Oracle数据库可以用定义视图的查询替换的视图。例如,假设您创建一个视图,如下所示:
CREATE OR REPLACE VIEW emp_view ASSELECT last_name, department_name FROM employees e, departments dWHERE e.department_id=d.department_id;
此视图是可合并的,因为数据库可以优化以下查询以使用定义视图的SELECT语句,从而避免使用视图本身。
SELECT * FROM emp_view;
视图中的优化方法和目标提示
优化方法和目标提示可以在顶级查询或内部视图中进行。
■如果顶级查询中存在此类提示,则数据库将使用此提示,而不管视图中是否有任何此类提示。
■如果没有顶级优化程序模式提示,则只要视图中的所有模式提示都一致,数据库就会在引用的视图中使用模式提示。
■如果引用视图中的两个或多个模式提示冲突,则数据库将丢弃视图中的所有模式提示,并使用会话模式,无论是默认还是用户指定。
访问路径和视图上的联接提示
除非视图包含单个表或引用带有单个表的Additional Hints视图,否则将忽略对引用视图的访问路径和连接提示。对于此类单表视图,视图上的访问路径提示或连接提示适用于视图内的表。
内部视图中的访问路径和连接提示
访问路径和连接提示可以显示在视图定义中。
■如果视图是内联视图(即,如果它出现在SELECT语句的FROM子句中),则当视图与顶级查询合并时,将保留视图内的所有访问路径和连接提示。
■对于非内联视图的视图,仅当引用查询不引用其他表或视图时(即,如果SELECT语句的FROM子句仅包含视图),才会保留视图中的访问路径和连接提示。
提示和不可合并的视图
使用不可合并的视图,忽略视图内的优化方法和目标提示;顶级查询决定优化模式。
由于不可合并的视图与顶级查询分开优化,因此将保留视图内的访问路径和连接提示。出于同样的原因,将忽略顶级查询中视图的访问路径提示。
但是,保留顶级查询中视图的连接提示,因为在这种情况下,不可合并的视图类似于表。