在 Oracle 中,连接查询(JOIN)
的连接类型及其性能对比
一、Oracle中的连接方式分类与语法
1. 内连接(INNER JOIN)
返回两个表中满足连接条件的记录。
SELECT *
FROM table1 t1
JOIN table2 t2 ON t1.id = t2.id;
特点:
- 只返回匹配的行。
- 是最常用的连接。
- 如果不指定连接方式(如使用
,
和WHERE
),默认是内连接。
2. 外连接(OUTER JOIN)
a)左外连接(LEFT OUTER JOIN)
返回左表的全部记录,如果右表中没有匹配的记录,则右表列为 NULL。
SELECT *
FROM table1 t1
LEFT JOIN table2 t2 ON t1.id = t2.id;
b)右外连接(RIGHT OUTER JOIN)
返回右表的全部记录,左表没有匹配记录的列为 NULL。
SELECT *
FROM table1 t1
RIGHT JOIN table2 t2 ON t1.id = t2.id;
c)全外连接(FULL OUTER JOIN)
返回两个表中的全部记录,没有匹配的部分列为 NULL。
SELECT *
FROM table1 t1
FULL OUTER JOIN table2 t2 ON t1.id = t2.id;
3. 自连接(SELF JOIN)
同一个表连接自身。
SELECT a.name, b.name
FROM employee a
JOIN employee b ON a.manager_id = b.id;
4. 交叉连接(CROSS JOIN)
返回两个表的笛卡尔积(每个表1条记录,两表组合1×1条记录)。
SELECT *
FROM table1
CROSS JOIN table2;
5. Oracle 专有语法:旧式连接 (+)
SELECT *
FROM table1 t1, table2 t2
WHERE t1.id = t2.id(+);
-- 等价于 LEFT JOIN
二、连接查询的性能效率比较
连接类型 | 行数大小关系 | 匹配情况 | 性能 | 优化建议 |
---|---|---|---|---|
INNER JOIN | 常见,性能最好 | 有匹配 | 高效 | 使用索引字段连接 |
LEFT JOIN | 左大右小 | 不一定匹配 | 中等 | 尽量加过滤条件 |
RIGHT JOIN | 左小右大 | 不一定匹配 | 中等 | 同上,尽量避免 |
FULL OUTER JOIN | 大数据慎用 | 不一定匹配 | 低效 | 避免在大数据量上使用 |
CROSS JOIN | 小表可用,谨慎使用 | 无条件连接 | 最低 | 通常不推荐 |
SELF JOIN | 中等 | 有匹配 | 中等 | 注意表别名 |
三、连接效率影响因素详解
1. 连接字段是否建索引
- 有索引:优化器可快速查找匹配项(Nested Loop)。
- 无索引:可能全表扫描(Hash Join、Merge Join)。
2. 表大小(数据量)
- 小表连接快,大表连接要谨慎。
- Oracle 优化器会根据统计信息选择合适连接方式。
3. 连接方式选择
INNER JOIN
优于OUTER JOIN
OUTER JOIN
多用于有缺失数据容忍时
4. Oracle 执行计划(EXPLAIN PLAN)
建议使用如下命令查看连接执行方式:
EXPLAIN PLAN FOR
SELECT ...
FROM ...
WHERE ...;
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY);
四、连接算法(Oracle执行时选择)
算法 | 特点 | 适用情况 |
---|---|---|
Nested Loop Join | 一条一条查找 | 小表驱动大表,有索引时最佳 |
Hash Join | 建立哈希表进行匹配 | 大表连接,大量数据无索引时 |
Merge Join | 对两个表排序再合并 | 连接列已排序或排序开销可接受 |
五、性能优化建议
- 优先使用 INNER JOIN,避免 FULL OUTER JOIN。
- 连接字段建立索引(特别是被驱动表的连接键)。
- 使用 WHERE 限定连接数据范围。
- 避免连接过多大表(建议 ≤ 4 张表)。
- 开启并更新表的统计信息,使 Oracle 优化器选择最佳执行计划。
- 避免在连接字段上使用函数或类型转换,否则索引失效。
- 使用临时表(WITH 或 MATERIALIZED VIEW)分步处理复杂连接逻辑
高效连接案例
多表连接,带索引、过滤条件
SELECT o.order_id, c.customer_name, p.product_name
FROM orders o
JOIN customers c ON o.customer_id = c.customer_id
JOIN products p ON o.product_id = p.product_id
WHERE o.order_date >= SYSDATE - 30;
- 三表 INNER JOIN
- 所有连接字段建立索引
- 限定最近 30 天数据,减少扫描量