1. 什么是 Hints?
Hints(提示) 是嵌入在 SQL 语句中的特殊注释,它为 Oracle 数据库优化器(Optimizer)提供指令或“提示”,旨在影响 SQL 语句的执行计划。
核心思想:通常情况下,Oracle 的优化器会自动为 SQL 语句选择它认为最优的执行计划(比如选择哪个索引、使用哪种连接方式等)。但有时候,优化器可能因为信息不准确(如陈旧的统计信息)或 SQL 的复杂性而无法做出最佳选择。Hints 允许有经验的开发者或DBA手动干预,强制优化器采用特定的路径,以期提升性能。
2. Hints 的基本语法
Hints 必须紧跟在 SELECT、UPDATE、INSERT、DELETE 或 MERGE 关键字之后,并放在 /*+ ... */ 注释中。
语法结构:
SELECT /*+ HINT_NAME [ ( argument [ , ... ] ) ] */ column1, column2...
FROM table_name
WHERE ...;
或者使用 --+ 的风格(较少用):
SELECT --+ HINT_NAME
column1, column2...
FROM table_name
WHERE ...;
重要注意事项:
- 语法必须精确:
/*+之间不能有空格,必须是/*+。*/用于结束提示。 - 位置必须正确:必须紧跟在 SQL 语句的第一个关键字之后。如果语句开头有
INSERT,提示就跟在INSERT后面。 - 拼写正确:Hint 名称拼写错误不会报错,但会被优化器静默忽略,这是最常见的问题之一。你可以通过查询执行计划(如
EXPLAIN PLAN)来确认 Hint 是否生效。
3. 常用且重要的 Hints 分类与示例
a. 优化器目标 Hints
告诉优化器是优先考虑响应速度还是整体资源消耗。
/*+ FIRST_ROWS(n) */:优先优化以最快速度返回前 n 条记录。适用于分页查询或用户交互式系统。SELECT /*+ FIRST_ROWS(10) */ * FROM orders ORDER BY order_date DESC;/*+ ALL_ROWS */:优化以最低的整体成本完成整个查询。适用于批处理作业、数据仓库报表等需要处理全部数据的场景。SELECT /*+ ALL_ROWS */ COUNT(*), customer_id FROM orders GROUP BY customer_id;
b. 表访问路径 Hints
指定访问表(或索引)的方式。
/*+ FULL(table_name) */:强制对指定表进行全表扫描。当表很小或需要访问大部分数据块时,全表扫描可能比索引扫描更高效。SELECT /*+ FULL(e) */ * FROM employees e WHERE salary > 5000;/*+ INDEX(table_name index_name) */:强制优化器使用特定的索引。当你确信某个索引比优化器选择的更优时使用。SELECT /*+ INDEX(emp emp_email_uk) */ employee_id FROM employees emp WHERE email = 'SKING';/*+ INDEX_FFS(table_name index_name) */:执行索引快速全扫描。它像全表扫描一样快速读取整个索引段(多块读取),适用于查询只访问索引列且需要大量数据的情况。SELECT /*+ INDEX_FFS(emp emp_name_ix) */ first_name, last_name FROM employees emp;
c. 表连接顺序 Hints
影响多表连接时表的顺序。
/*+ ORDERED */:强制优化器按照FROM子句中表出现的顺序进行连接。SELECT /*+ ORDERED */ e.last_name, d.department_name FROM departments d, employees e WHERE e.department_id = d.department_id; -- 先扫描 departments,再连接 employees
d. 表连接方法 Hints
指定表之间使用哪种连接算法。
/*+ USE_NL(table1 table2) */:强制对指定表使用嵌套循环连接。适用于驱动表(小表)返回结果集很小的情况。SELECT /*+ USE_NL(e d) */ e.last_name, d.department_name FROM employees e, departments d WHERE e.department_id = d.department_id;/*+ USE_HASH(table1 table2) */:强制对指定表使用哈希连接。通常适用于大量数据且连接条件为等值连接的情况。SELECT /*+ USE_HASH(e d) */ e.last_name, d.department_name FROM employees e, departments d WHERE e.department_id = d.department_id;/*+ USE_MERGE(table1 table2) */:强制对指定表使用排序合并连接。适用于非等值连接(如<,>=)或两个表都已排序的情况。
e. 并行执行 Hints
利用多CPU核心来加速操作,主要用于数据仓库环境。
/*+ PARALLEL(table_name, degree) */:指示优化器对指定表使用指定程度的并行查询。degree是并行度(线程数)。SELECT /*+ PARALLEL(sales, 8) */ SUM(amount_sold) FROM sales;
4. 使用 Hints 的注意事项与最佳实践
-
最后的手段:Hints 应该是性能调优的最后选择,而不是首选。优先考虑:
- 收集最新的统计信息 (
DBMS_STATS.GATHER_TABLE_STATS)。 - 优化 SQL 语句结构和写法。
- 创建或修改索引。
- 调整数据库参数。
- 收集最新的统计信息 (
-
难以维护:Hints 被硬编码在 SQL 中。如果数据库环境发生变化(如数据量剧增、索引变更、Oracle 版本升级),一个今天有效的 Hint 明天可能会成为性能瓶颈,而你需要手动发现和修改它。
-
可能被忽略:如果 Hint 语法错误、逻辑上不可能实现(如要求使用一个不存在的索引)或与优化器模式冲突,Oracle 会静默忽略它,而不是报错。你必须检查执行计划来确认 Hint 是否生效。
-
谨慎使用:错误地使用 Hints(如在小表上强制全表扫描,在大表上强制嵌套循环连接)可能会导致性能灾难。
-
使用 SQL Plan Management (SPM):在 Oracle 11g 及更高版本中,可以考虑使用 SPM 来固定一个已知良好的执行计划,这比使用 Hints 更灵活和强大。
总结
| 特性 | 描述 |
|---|---|
| 是什么 | 嵌入在 SQL 注释中的指令,用于影响优化器的决策。 |
| 为什么用 | 在优化器无法自动选择最佳执行计划时,手动指导其行为以提升性能。 |
| 怎么用 | SELECT /*+ HINT_NAME(参数) */ ...,紧跟在第一个关键字后。 |
| 优点 | 能够快速解决特定的性能问题。 |
| 缺点 | 硬编码、难以维护、可能过时、使用不当会降低性能、可能被静默忽略。 |
| 建议 | 慎用! 优先使用统计信息、索引、SQL 重构等标准方法。将其视为一把需要小心挥舞的“手术刀”,而非“万能锤”。 |

638

被折叠的 条评论
为什么被折叠?



