HASH JOIN 跟NESTED LOOP 快一个列子

本文对比了NESTED LOOP与HASH JOIN两种连接方式在处理大量数据时的性能差异,发现HASH JOIN在相同条件下运行速度远超NESTED LOOP。文章通过具体案例展示了如何通过选择合适的连接方法来提高SQL查询效率。

在报表库的每个小时数据量23113条时候

NESTED LOOP 要跑3分钟 而 HASH JOIN 才7秒钟

NESTED LOOP:

SELECT *
FROM ( SELECT ACTIONID,
OPCONTENTID,
MOUDULEID,
PORTALID,
'lars01.OP_MAIL_VISIT_04_1105' AS table_name,
TO_DATE (20110501000000, 'yyyymmddhh24miss') + (9 / 24)
AS INSERTTIME_START,
TRUNC (TO_DATE (20110501000000, 'yyyymmddhh24miss'))
+ ( (9 + 1) / 24)
AS INSERTTIME_END,
MIN (RECORDID) AS RECORDID,
COUNT (1) AS row_num
FROM lars01.OP_MAIL_VISIT_03_1104
WHERE inserttime >=
TO_DATE (20110501000000, 'yyyymmddhh24miss') + (9 / 24)
AND inserttime <
TRUNC (TO_DATE (20110501000000, 'yyyymmddhh24miss'))
+ ( (9 + 1) / 24)
GROUP BY ACTIONID,
OPCONTENTID,
MOUDULEID,
PORTALID) t
LEFT JOIN
(SELECT DISTINCT action_id,
module_iD,
portal_id,
opcontent_id
FROM etl_rule s
WHERE rule_valid = 1
AND rule_type = '点击 '
AND TO_CHAR (action_id) IN (SELECT *
FROM TABLE (
SELECT f_etl_proc (
check_value01
|| ','
|| check_value02)
FROM etl_condition
WHERE condition_id =
3))) s
ON ( t.actionid = s.action_id
AND t.opcontentid = s.opcontent_id
AND t.MOUDULEID = s.module_iD
AND t.PORTALID = s.portal_id)
WHERE action_id IS NULL

DBA 说 etl_rule每条记录都要全表扫描 TABLE() 在开发库单独拿出该语句执行要122秒

而HASH JOIN 只要2.04秒

HASH JOIN:

SELECT *
FROM ( SELECT ACTIONID,
OPCONTENTID,
MOUDULEID,
PORTALID,
'lars01.OP_MAIL_VISIT_04_1105' AS table_name,
TO_DATE (20110501000000, 'yyyymmddhh24miss') + (9 / 24)
AS INSERTTIME_START,
TRUNC (TO_DATE (20110501000000, 'yyyymmddhh24miss'))
+ ( (9 + 1) / 24)
AS INSERTTIME_END,
MIN (RECORDID) AS RECORDID,
COUNT (1) AS row_num
FROM lars01.OP_MAIL_VISIT_03_1104
WHERE inserttime >=
TO_DATE (20110501000000, 'yyyymmddhh24miss') + (9 / 24)
AND inserttime <
TRUNC (TO_DATE (20110501000000, 'yyyymmddhh24miss'))
+ ( (9 + 1) / 24)
GROUP BY ACTIONID,
OPCONTENTID,
MOUDULEID,
PORTALID) t
LEFT JOIN
(SELECT DISTINCT action_id,
module_iD,
portal_id,
opcontent_id
FROM etl_rule s,(SELECT *
FROM TABLE (
SELECT f_etl_proc (
check_value01
|| ','
|| check_value02)
FROM etl_condition
WHERE condition_id =
3)) b
WHERE rule_valid = 1
AND rule_type = '点击 '
AND TO_CHAR (action_id) = b.column_value
) s
ON ( t.actionid = s.action_id
AND t.opcontentid = s.opcontent_id
AND t.MOUDULEID = s.module_iD
AND t.PORTALID = s.portal_id)
WHERE action_id IS NULL

<think>好的,我需要详细解释Oracle中HashJoinNestedLoop的区别以及它们的适用场景。首先,我需要回顾用户提供的引用内容,确保准确引用相关信息。用户给出的引用[1]、[2]、[3]、[4]主要涉及两种连接方式的比较、优化器提示(如Leading和use_hash)、效率比较以及适用场景。我需要综合这些信息,整理出两者的核心区别和使用场景。首先,Hash JoinNested Loop的基本区别在于工作机制。Nested Loop是双重循环,适合小数据集,而HashJoin处理大数据集时更高效。引用[3]提到,NestedLoop通常用小表作为驱动表,而Hash Join适合大表连接。引用[4]也指出HashJoin在大表间更,而Nested Loop在小表且有索引时更优。接下来需要明确两者的适用场景。例如,当驱动表结果集小且连接字段有索引时,Nested Loop更有效。而Hash Join在没有索引或数据量大时表现更好,但需要足够内存构建哈希表。引用[2]中的use_hash提示可以强制使用Hash Join,说明在优化器选择不当时可以手动干预。 还要注意两者的性能影响因素。Nested Loop依赖索引和驱动表大小,Hash Join则受内存和哈希表构建的影响。引用[1]提到Leading可以调整连接顺序,这可能影响两种连接方式的选择。最后,要确保回答结构清晰,分点说明区别和场景,并加入示例帮助理解。同时,生成的相关问题需要与主题紧密相关,如优化方法、如何选择连接方式等。</think>### Hash JoinNested Loop的区别及适用场景 #### 一、核心区别 1. **工作机制** - **Nested Loop(嵌套循环)** 通过双重循环匹配数据,类似以下伪代码逻辑: ``` FOR 驱动表每一行r1 DO FOR 被驱动表每一行r2 DO IF r1.key = r2.key THEN 返回结果 ``` 适合驱动表结果集小且被驱动表有高效索引的场景[^3][^4]。 - **Hash Join(哈希连接)** 分为两步: - **构建阶段**:扫描驱动表,在内存中构建哈希表(Key为连接字段的哈希值) - **探测阶段**:扫描被驱动表,计算哈希值并匹配内存中的哈希表 适合数据量大且无索引的场景,但需要足够内存存放哈希表[^1][^4]。 2. **性能对比** | 指标 | Nested Loop | Hash Join | |---------------|----------------------|------------------------| | 时间复杂度 | $O(M \times N)$ | $O(M + N)$(理想情况) | | 内存消耗 | 低(仅需索引缓存) | 高(需存储哈希表) | | 适用数据量 | 小数据集(如千级) | 大数据集(如百万级) | #### 二、适用场景 1. **优先使用Nested Loop的情况** - 驱动表经过过滤后返回的行数较少(例如$<1\%$总数据) - 被驱动表的连接字段上有高效索引(如B-tree索引) - 示例: ```sql -- 强制使用Nested Loop SELECT /*+ USE_NL(orders, customers) */ * FROM orders JOIN customers ON orders.cust_id = customers.id WHERE customers.country = 'US'; -- 假设country过滤后仅剩100行 ``` *若`customers.id`有索引,可速定位被驱动表数据*[^3][^4]。 2. **优先使用Hash Join的情况** - 表之间无有效索引,或数据量过大导致索引效率下降 - 内存充足,可容纳驱动表的哈希表 - 需要处理全表或大部分数据(例如$>20\%$总数据) - 示例: ```sql -- 强制使用Hash Join SELECT /*+ USE_HASH(sales, products) */ * FROM sales JOIN products ON sales.product_id = products.id; -- 假设两表均为千万级 ``` *若无索引,Hash Join可避免全表扫描的随机I/O*[^1][^4]。 #### 三、优化器干预 Oracle优化器可能因统计信息不准确选择次优连接方式,此时可通过提示(Hint)调整: - **`USE_NL`**:强制使用Nested Loop ```sql SELECT /*+ USE_NL(a, b) */ * FROM table_a a JOIN table_b b ON a.id = b.id; ``` - **`USE_HASH`**:强制使用Hash Join ```sql SELECT /*+ USE_HASH(a, b) */ * FROM table_a a JOIN table_b b ON a.id = b.id; ``` - **`LEADING`**:指定驱动表顺序 ```sql SELECT /*+ LEADING(a) USE_NL(b) */ * FROM table_a a JOIN table_b b ON a.id = b.id; ``` *指定`a`为驱动表并强制Nested Loop*[^1][^2]。 --- ### 性能对比实验(引用[4]案例) | 场景 | Nested Loop耗时 | Hash Join耗时 | |---------------------|-----------------|---------------| | 小表(1万行)+ 大表(100万行) | 2秒 | 15秒 | | 大表(100万行)+ 大表(100万行) | 超时(>300秒) | 25秒 | *结论:小表驱动时Nested Loop更优,大表间Hash Join更高效*[^4]。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值