在达梦数据库的查询优化过程中,连接算子的选择对查询性能有着决定性影响。本文将详细介绍达梦数据库中常用的连接算子,包括其工作原理、典型用例及优化建议,帮助大家更加深入的理解达梦JOIN算子。
达梦数据库的连接算子主要分为嵌套循环连接(NEST LOOP JOIN)、哈希连接(HASH JOIN)、归并连接(MERGE JOIN) 和索引连接(INDEX JOIN) 四大类,各类算子针对不同数据场景设计,核心功能差异显著。
达梦数据库的连接算子主要分为嵌套循环连接(NEST LOOP JOIN)、哈希连接(HASH JOIN)、归并连接(MERGE JOIN) 和索引连接(INDEX JOIN) 四大类,各类算子针对不同数据场景设计,核心功能差异显著。
嵌套循环连接通过 “外层表遍历 + 内层表匹配” 的方式实现连接,适用于小表连接或被驱动表表有高效索引的场景,核心优势是资源开销消耗低、支持非等值连接、执行逻辑简单等。
(1)NEST LOOP INDEX JOIN2:索引内连接,被驱动表通过索引快速查找匹配数据,仅返回两表匹配的记录,依赖内层表的连接列索引提升查找效率。
u.username,
SUM(o.amount) AS total_amount
FROM
users u
JOIN
orders o ON u.user_id = o.user_id
GROUP BY
u.user_id, u.username;
(2)NEST LOOP FULL JOIN2:嵌套循环全外连接,驱动表逐行扫描,被驱动表针对每行数据进行匹配查询,返回两个表中所有匹配与不匹配的记录,无论是否找到关联数据,两端表的记录都会保留,通过嵌套循环逻辑处理全外连接的补全逻辑。
e.emp_name,
d.dept_name,
d.location AS
FROM employees e
FULL JOIN departments d
ON e.dept_id = d.dept_id
ORDER BY e.emp_id;
(3)NEST LOOP INNER JOIN2:基础嵌套循环内连接,仅保留两表中满足连接条件的记录。
SELECT /*+ USE_NL(d, e) */
d.dept_name,
COUNT(e.emp_id) as emp_count
FROM departments_nl d
INNER JOIN employees_nl e ON d.dept_id = e.dept_id
GROUP BY d.dept_name
ORDER BY emp_count DESC;
(4)NEST LOOP LEFT JOIN2:嵌套循环左外连接,保留左表所有记录。
SELECT d.dept_name,
p.project_name,
COALESCE(p.start_date, '无项目') as project_start
FROM departments d
LEFT JOIN projects p ON d.dept_id = p.dept_id
AND p.start_date >= '2024-01-01';
(5)NEST LOOP SEMI JOIN2:嵌套循环半连接,仅返回左表中存在匹配右表记录的行。
SELECT d.dept_id, d.dept_name
FROM departments d
WHERE EXISTS (
SELECT 1 FROM projects p
WHERE p.dept_id = d.dept_id
);
哈希连接通过 “构建哈希表 + 探测匹配” 的逻辑实现连接,适用于大表连接或无有效索引的场景,核心优势是处理大量数据时效率稳定。
(1)HASH FULL JOIN2:哈希全外连接。
CASE
WHEN d.dept_id IS NULL THEN '缺失部门:员工无对应部门'
WHEN e.emp_id IS NULL THEN '缺失员工:部门无对应员工'
ELSE '正常匹配'
END as 检查结果,
d.dept_id,
d.dept_name,
e.emp_id,
e.emp_name
FROM departments d
FULL OUTER JOIN employees e ON d.dept_id = e.dept_id
WHERE d.dept_id IS NULL OR e.emp_id IS NULL
ORDER BY 检查结果, d.dept_id, e.emp_id;
(2)HASH LEFT JOIN2:哈希左外连接。
SELECT d.dept_id, d.dept_name, e.emp_name, e.salary
FROM departments_hash d
LEFT JOIN employees_hash e ON d.dept_id = e.dept_id
WHERE d.budget > 200000;
(3)HASH LEFT SEMI MULTIPLE JOIN:达梦数据库处理多列NOT IN 时的算子。当子查询返回多列,且无法用索引时,优化器会用哈希表暴力匹配,但保留主表所有行。
SELECT p.product_name, p.category, p.price
FROM products p
WHERE (p.product_id, p.create_date) NOT IN (
SELECT o.product_id, o.order_date
FROM orders o
WHERE o.quantity >= 2
AND o.order_date >= '2024-01-01'
);
(4)HASH LEFT SEMI JOIN2:哈希左半连接。
'部门' as 来源,
d.dept_id as 部门ID,
d.dept_name as 部门名称,
NULL as 员工ID,
NULL as 员工姓名
FROM departments d
WHERE NOT EXISTS (
SELECT 1 FROM employees e
WHERE e.dept_id = d.dept_id
)
(5)HASH2 INNER JOIN:哈希内连接。
'匹配' as 来源,
d.dept_id as 部门ID,
d.dept_name as 部门名称,
e.emp_id as 员工ID,
e.emp_name as 员工姓名
FROM departments d
INNER JOIN employees e ON d.dept_id = e.dept_id
归并连接需先对两个表的连接列排序,再通过已排序后的数据实现有效数据范围内匹配,适用于连接列已排序或需排序输出的场景,核心优势是排序后匹配效率极高,且结果天然有序。
(1)MERGE INNER JOIN3:归并内连接,先对两表连接列分别排序(若已排序则跳过),再同步扫描两个有序表,当连接列值相等时返回匹配记录,适用于需要有序结果的大表连接。
SELECT
/*+ USE_MERGE(T1,T2) */
*
FROM T1,
T2
WHERE T1.ID = T2.ID
AND T1.ID < 1
AND T2.ID < 1;
(2)MERGE SEMI JOIN3:归并半连接,仅返回左表中存在右表匹配记录的行,且结果保持左表排序顺序,适用于需有序输出的半连接场景。
SELECT
/*+ USE_MERGE_SEMI(T1, T2) */
T1.*
FROM T1
WHERE T1.ID IN (SELECT T2.ID FROM T2)
AND T1.ID < 1;
索引连接直接利用表的索引完成连接,无需扫描全表,适用于连接列有高质量索引的场景,核心优势是查询延迟低、IO 消耗小。
(1)INDEX JOIN LEFT JOIN2:索引左外连接,左表扫描过程中,通过右表连接列的索引快速查找匹配数据,保留左表所有记录,避免右表全表扫描。
SELECT p.product_name, p.category, p.price
FROM products p
LEFT JOIN orders o
ON p.product_id = o.product_id
AND o.quantity >= 2
AND o.order_date BETWEEN '2024-01-01' AND '2024-02-28'
ORDER BY p.price DESC;
(2)INDEX JOIN SEMI JOIN2:索引半连接,左表逐行扫描时,通过右表索引判断是否存在匹配记录,仅返回左表中存在匹配的行,索引查找替代右表全表扫描,效率显著提升。
SELECT p.product_name, p.category, p.price, o.product_id
FROM products p
WHERE p.product_id IN (
SELECT o.product_id
FROM orders o
WHERE o.quantity >= 2
AND o.order_date BETWEEN '2024-01-01' AND '2024-02-28'
)
ORDER BY p.price DESC;
在达梦数据库进行数据关联时,若优化器选择的JOIN算子执行代价过高,可通过优化器提示(HINT)来调整连接策略。以下是常用的收集统计信息、HINT示例:
STAT 100 ON T1(ID);
--使用hash join进行关联
SELECT /*+ USE_HASH(a b) */ * FROM table1 a JOIN table2 b ...;
--当连接情况为左表+右表索引时,强制两个表间使用nestloop index join进行关联
SELECT /*+ USE_NL_WITH_INDEX(a b) */ * FROM table1 a JOIN table2 b ...;
--使用merge join进行关联
SELECT /*+ USE_MERGE(a b) */ * FROM table1 a JOIN table2 b ...;
本文如有疏漏或不准确之处,敬请批评指正。
文章
阅读量
获赞
