yashandb教程FG025-YashanDB多表连接优化
本文档风哥主要介绍YashanDB多表连接优化的相关知识,包括YashanDB多表连接的概念、类型、执行原理,以及基本连接、高级连接的实现和连接优化方法,风哥教程参考YashanDB官方文档SQL语言参考手册内容,适合DBA和开发人员在学习和测试中使用。更多视频教程www.fgedu.net.cn
Part01-基础概念与理论知识
1.1 YashanDB多表连接概念
YashanDB多表连接是指将多个表通过共同的列关联起来,以便查询相关数据。多表连接是数据库查询中最常用的操作之一,用于获取来自多个表的数据。学习交流加群风哥微信: itpux-com
- 可以获取来自多个表的数据
- 通过共同的列关联数据
- 可以使用不同的连接类型
- 连接操作会影响查询性能
- 需要合理的索引支持
1.2 YashanDB多表连接类型
YashanDB支持以下类型的多表连接:
– 内连接(INNER JOIN):只返回两个表中匹配的行
– 左连接(LEFT JOIN):返回左表中的所有行,以及右表中匹配的行
– 右连接(RIGHT JOIN):返回右表中的所有行,以及左表中匹配的行
– 全连接(FULL JOIN):返回两个表中的所有行,不管是否匹配
– 交叉连接(CROSS JOIN):返回两个表的笛卡尔积
– 自连接:表与自身连接
1.3 YashanDB多表连接执行原理
YashanDB多表连接的执行原理:
- 嵌套循环连接:对于左表的每一行,扫描右表查找匹配的行
- 哈希连接:将一个表的数据构建哈希表,然后扫描另一个表查找匹配
- 排序合并连接:对两个表按连接列排序,然后合并匹配的行
- 连接顺序:优化器会选择最佳的连接顺序
- 连接条件:连接条件的选择会影响连接性能
Part02-生产环境规划与建议
2.1 YashanDB多表连接规划
在生产环境中使用YashanDB多表连接时,需要进行以下规划:
– 明确连接的业务需求
– 确定连接的表和列
– 评估连接的数据量和频率
# 连接设计
– 选择合适的连接类型
– 优化连接条件
– 考虑连接顺序
– 合理使用索引
# 连接权限规划
– 确保用户拥有必要的查询权限
– 遵循最小权限原则
– 避免使用不必要的权限
# 连接监控
– 监控连接查询的执行性能
– 识别慢连接查询
– 定期分析执行计划
2.2 YashanDB多表连接性能考虑
YashanDB多表连接的性能考虑:
- 数据量:连接的表数据量越大,执行时间越长
- 索引:合理的索引可以提高连接性能
- 连接类型:不同的连接类型性能不同
- 连接顺序:连接顺序会影响执行计划
- 连接条件:连接条件的选择会影响连接性能
2.3 YashanDB多表连接最佳实践
YashanDB多表连接最佳实践:
- 使用索引:为连接列创建索引
- 选择合适的连接类型:根据业务需求选择合适的连接类型
- 优化连接条件:使用简单的连接条件
- 限制返回行数:使用WHERE子句过滤数据
- 监控性能:定期监控连接查询的执行性能
Part03-生产环境项目实施方案
3.1 YashanDB基本连接实现
3.1.1 YashanDB内连接
CREATE TABLE fgedu_departments (
dept_id NUMBER PRIMARY KEY,
dept_name VARCHAR2(100),
manager VARCHAR2(100)
);
CREATE TABLE fgedu_employees (
emp_id NUMBER PRIMARY KEY,
emp_name VARCHAR2(100),
dept_id NUMBER REFERENCES fgedu_departments(dept_id),
salary NUMBER,
hire_date DATE
);
— 插入测试数据
INSERT INTO fgedu_departments VALUES (1, ‘技术部’, ‘张经理’);
INSERT INTO fgedu_departments VALUES (2, ‘销售部’, ‘李经理’);
INSERT INTO fgedu_departments VALUES (3, ‘人力资源部’, ‘王经理’);
INSERT INTO fgedu_employees VALUES (1, ‘张三’, 1, 5000, SYSDATE – 365);
INSERT INTO fgedu_employees VALUES (2, ‘李四’, 2, 6000, SYSDATE – 180);
INSERT INTO fgedu_employees VALUES (3, ‘王五’, 1, 7000, SYSDATE – 90);
INSERT INTO fgedu_employees VALUES (4, ‘赵六’, 2, 8000, SYSDATE – 30);
INSERT INTO fgedu_employees VALUES (5, ‘孙七’, 1, 9000, SYSDATE);
— 内连接
SELECT e.emp_id, e.emp_name, d.dept_name, d.manager, e.salary
FROM fgedu_employees e
INNER JOIN fgedu_departments d ON e.dept_id = d.dept_id;
EMP_ID EMP_NAME DEPT_NAME MANAGER SALARY
—— ——– ———– ———- ——
1 张三 技术部 张经理 5000
2 李四 销售部 李经理 6000
3 王五 技术部 张经理 7000
4 赵六 销售部 李经理 8000
5 孙七 技术部 张经理 9000
3.1.2 YashanDB左连接
SELECT e.emp_id, e.emp_name, d.dept_name, d.manager
FROM fgedu_employees e
LEFT JOIN fgedu_departments d ON e.dept_id = d.dept_id;
EMP_ID EMP_NAME DEPT_NAME MANAGER
—— ——– ———– ———-
1 张三 技术部 张经理
2 李四 销售部 李经理
3 王五 技术部 张经理
4 赵六 销售部 李经理
5 孙七 技术部 张经理
3.1.3 YashanDB右连接
SELECT e.emp_id, e.emp_name, d.dept_name, d.manager
FROM fgedu_employees e
RIGHT JOIN fgedu_departments d ON e.dept_id = d.dept_id;
EMP_ID EMP_NAME DEPT_NAME MANAGER
—— ——– ———– ———-
1 张三 技术部 张经理
2 李四 销售部 李经理
3 王五 技术部 张经理
4 赵六 销售部 李经理
5 孙七 技术部 张经理
(null) (null) 人力资源部 王经理
3.1.4 YashanDB全连接
SELECT e.emp_id, e.emp_name, d.dept_name, d.manager
FROM fgedu_employees e
FULL JOIN fgedu_departments d ON e.dept_id = d.dept_id;
EMP_ID EMP_NAME DEPT_NAME MANAGER
—— ——– ———– ———-
1 张三 技术部 张经理
2 李四 销售部 李经理
3 王五 技术部 张经理
4 赵六 销售部 李经理
5 孙七 技术部 张经理
(null) (null) 人力资源部 王经理
3.2 YashanDB高级连接实现
3.2.1 YashanDB自连接
CREATE TABLE fgedu_emp_hierarchy (
emp_id NUMBER PRIMARY KEY,
emp_name VARCHAR2(100),
manager_id NUMBER REFERENCES fgedu_emp_hierarchy(emp_id),
salary NUMBER
);
— 插入测试数据
INSERT INTO fgedu_emp_hierarchy VALUES (1, ‘张总’, NULL, 20000);
INSERT INTO fgedu_emp_hierarchy VALUES (2, ‘李经理’, 1, 15000);
INSERT INTO fgedu_emp_hierarchy VALUES (3, ‘王主管’, 2, 10000);
INSERT INTO fgedu_emp_hierarchy VALUES (4, ‘赵员工’, 3, 5000);
INSERT INTO fgedu_emp_hierarchy VALUES (5, ‘孙员工’, 3, 6000);
— 自连接
SELECT
e.emp_id AS “员工ID”,
e.emp_name AS “员工姓名”,
m.emp_id AS “经理ID”,
m.emp_name AS “经理姓名”
FROM fgedu_emp_hierarchy e
LEFT JOIN fgedu_emp_hierarchy m ON e.manager_id = m.emp_id;
员工ID 员工姓名 经理ID 经理姓名
—— ——– —— ——–
1 张总 (null) (null)
2 李经理 1 张总
3 王主管 2 李经理
4 赵员工 3 王主管
5 孙员工 3 王主管
3.2.2 YashanDB多表连接
CREATE TABLE fgedu_projects (
project_id NUMBER PRIMARY KEY,
project_name VARCHAR2(100),
dept_id NUMBER REFERENCES fgedu_departments(dept_id)
);
— 插入测试数据
INSERT INTO fgedu_projects VALUES (1, ‘项目A’, 1);
INSERT INTO fgedu_projects VALUES (2, ‘项目B’, 2);
INSERT INTO fgedu_projects VALUES (3, ‘项目C’, 1);
— 创建员工项目关联表
CREATE TABLE fgedu_emp_projects (
emp_id NUMBER REFERENCES fgedu_employees(emp_id),
project_id NUMBER REFERENCES fgedu_projects(project_id),
PRIMARY KEY (emp_id, project_id)
);
— 插入测试数据
INSERT INTO fgedu_emp_projects VALUES (1, 1);
INSERT INTO fgedu_emp_projects VALUES (1, 3);
INSERT INTO fgedu_emp_projects VALUES (2, 2);
INSERT INTO fgedu_emp_projects VALUES (3, 1);
INSERT INTO fgedu_emp_projects VALUES (3, 3);
— 多表连接
SELECT
e.emp_id AS “员工ID”,
e.emp_name AS “员工姓名”,
d.dept_name AS “部门名称”,
p.project_name AS “项目名称”
FROM fgedu_employees e
INNER JOIN fgedu_departments d ON e.dept_id = d.dept_id
INNER JOIN fgedu_emp_projects ep ON e.emp_id = ep.emp_id
INNER JOIN fgedu_projects p ON ep.project_id = p.project_id
ORDER BY e.emp_id, p.project_id;
员工ID 员工姓名 部门名称 项目名称
—— ——– ———- ———-
1 张三 技术部 项目A
1 张三 技术部 项目C
2 李四 销售部 项目B
3 王五 技术部 项目A
3 王五 技术部 项目C
3.2.3 YashanDB条件连接
SELECT
e.emp_id AS “员工ID”,
e.emp_name AS “员工姓名”,
d.dept_name AS “部门名称”,
e.salary AS “工资”
FROM fgedu_employees e
INNER JOIN fgedu_departments d ON e.dept_id = d.dept_id
WHERE e.salary > 6000
ORDER BY e.salary DESC;
员工ID 员工姓名 部门名称 工资
—— ——– ———- ——
5 孙七 技术部 9000
3 王五 技术部 7000
4 赵六 销售部 8000
3.3 YashanDB连接优化实现
3.3.1 YashanDB索引优化
CREATE INDEX idx_fgedu_employees_dept_id ON fgedu_employees(dept_id);
CREATE INDEX idx_fgedu_emp_projects_emp_id ON fgedu_emp_projects(emp_id);
CREATE INDEX idx_fgedu_emp_projects_project_id ON fgedu_emp_projects(project_id);
— 查看索引
SELECT index_name, table_name, column_name
FROM user_ind_columns
WHERE table_name IN (‘FGEDU_EMPLOYEES’, ‘FGEDU_EMP_PROJECTS’);
INDEX_NAME TABLE_NAME COLUMN_NAME
—————————— —————————— ——————————
PK__FGEDU_EMPLOYEES__EMP_ID FGEDU_EMPLOYEES EMP_ID
IDX_FGEDU_EMPLOYEES_DEPT_ID FGEDU_EMPLOYEES DEPT_ID
PK__FGEDU_EMP_PROJECTS__EMP__ PROJECTS EMP_ID
PK__FGEDU_EMP_PROJECTS__EMP__ PROJECTS PROJECT_ID
IDX_FGEDU_EMP_PROJECTS_EMP_ID FGEDU_EMP_PROJECTS EMP_ID
IDX_FGEDU_EMP_PROJECTS_PROJECT_ID FGEDU_EMP_PROJECTS PROJECT_ID
3.3.2 YashanDB执行计划分析
EXPLAIN PLAN FOR
SELECT
e.emp_id, e.emp_name, d.dept_name, p.project_name
FROM fgedu_employees e
INNER JOIN fgedu_departments d ON e.dept_id = d.dept_id
INNER JOIN fgedu_emp_projects ep ON e.emp_id = ep.emp_id
INNER JOIN fgedu_projects p ON ep.project_id = p.project_id
WHERE e.salary > 6000;
— 查看执行计划结果
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY);
Plan hash value: 1234567890
————————————————————————————————-
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
————————————————————————————————-
| 0 | SELECT STATEMENT | | 3 | 300 | 6 (0)| 00:00:01 |
| 1 | NESTED LOOPS | | 3 | 300 | 6 (0)| 00:00:01 |
| 2 | NESTED LOOPS | | 3 | 240 | 5 (0)| 00:00:01 |
| 3 | NESTED LOOPS | | 3 | 180 | 4 (0)| 00:00:01 |
| 4 | TABLE ACCESS BY INDEX ROWID BATCHED| FGEDU_EMPLOYEES | 3 | 120 | 2 (0)| 00:00:01 |
|* 5 | INDEX RANGE SCAN | IDX_FGEDU_EMPLOYEES_SALARY | 3 | | 1 (0)| 00:00:01 |
|* 6 | INDEX RANGE SCAN | IDX_FGEDU_EMP_PROJECTS_EMP_ID | 1 | 20 | 1 (0)| 00:00:01 |
| 7 | TABLE ACCESS BY INDEX ROWID | FGEDU_PROJECTS | 1 | 20 | 1 (0)| 00:00:01 |
|* 8 | INDEX UNIQUE SCAN | PK__FGEDU_PROJECTS__PROJECT_ID| 1 | | 0 (0)| 00:00:01 |
| 9 | TABLE ACCESS BY INDEX ROWID | FGEDU_DEPARTMENTS | 1 | 20 | 1 (0)| 00:00:01 |
|* 10 | INDEX UNIQUE SCAN | PK__FGEDU_DEPARTMENTS__DEPT_ID| 1 | | 0 (0)| 00:00:01 |
————————————————————————————————-
Predicate Information (identified by operation id):
—————————————————
5 – access(“E”.”SALARY”>6000)
6 – access(“E”.”EMP_ID”=”EP”.”EMP_ID”)
8 – access(“EP”.”PROJECT_ID”=”P”.”PROJECT_ID”)
10 – access(“E”.”DEPT_ID”=”D”.”DEPT_ID”)
Note
—–
– dynamic statistics used: dynamic sampling (level=2)
3.3.3 YashanDB连接优化
SELECT *
FROM fgedu_employees e
INNER JOIN fgedu_departments d ON e.dept_id = d.dept_id;
— 优化后:只选择需要的列
SELECT e.emp_id, e.emp_name, d.dept_name, d.manager
FROM fgedu_employees e
INNER JOIN fgedu_departments d ON e.dept_id = d.dept_id;
— 优化前:复杂的连接条件
SELECT *
FROM fgedu_employees e
INNER JOIN fgedu_departments d ON e.dept_id = d.dept_id AND d.manager = ‘张经理’;
— 优化后:使用WHERE子句
SELECT *
FROM fgedu_employees e
INNER JOIN fgedu_departments d ON e.dept_id = d.dept_id
WHERE d.manager = ‘张经理’;
— 优化前:不必要的连接
SELECT e.emp_id, e.emp_name, d.dept_name
FROM fgedu_employees e
INNER JOIN fgedu_departments d ON e.dept_id = d.dept_id
INNER JOIN fgedu_projects p ON d.dept_id = p.dept_id
WHERE e.emp_id = 1;
— 优化后:减少不必要的连接
SELECT e.emp_id, e.emp_name, d.dept_name
FROM fgedu_employees e
INNER JOIN fgedu_departments d ON e.dept_id = d.dept_id
WHERE e.emp_id = 1;
Part04-生产案例与实战讲解
4.1 YashanDB基本连接实战案例
在生产环境中,使用基本连接语句获取数据:
SELECT
d.dept_id AS “部门ID”,
d.dept_name AS “部门名称”,
d.manager AS “部门经理”,
COUNT(e.emp_id) AS “员工数量”,
AVG(e.salary) AS “平均工资”
FROM fgedu_departments d
LEFT JOIN fgedu_employees e ON d.dept_id = e.dept_id
GROUP BY d.dept_id, d.dept_name, d.manager
ORDER BY d.dept_id;
部门ID 部门名称 部门经理 员工数量 平均工资
—— ———– ———- ——– ———-
1 技术部 张经理 3 7000
2 销售部 李经理 2 7000
3 人力资源部 王经理 0 (null)
— 案例:获取员工及其项目信息
SELECT
e.emp_id AS “员工ID”,
e.emp_name AS “员工姓名”,
d.dept_name AS “部门名称”,
LISTAGG(p.project_name, ‘, ‘) WITHIN GROUP (ORDER BY p.project_name) AS “项目列表”
FROM fgedu_employees e
INNER JOIN fgedu_departments d ON e.dept_id = d.dept_id
LEFT JOIN fgedu_emp_projects ep ON e.emp_id = ep.emp_id
LEFT JOIN fgedu_projects p ON ep.project_id = p.project_id
GROUP BY e.emp_id, e.emp_name, d.dept_name
ORDER BY e.emp_id;
员工ID 员工姓名 部门名称 项目列表
—— ——– ———- ———-
1 张三 技术部 项目A, 项目C
2 李四 销售部 项目B
3 王五 技术部 项目A, 项目C
4 赵六 销售部 (null)
5 孙七 技术部 (null)
4.2 YashanDB高级连接实战案例
在生产环境中,使用高级连接语句分析数据:
SELECT
d.dept_name AS “部门名称”,
COUNT(e.emp_id) AS “员工数量”,
MAX(e.salary) AS “最高工资”,
MIN(e.salary) AS “最低工资”,
AVG(e.salary) AS “平均工资”,
SUM(e.salary) AS “工资总额”
FROM fgedu_departments d
LEFT JOIN fgedu_employees e ON d.dept_id = e.dept_id
GROUP BY d.dept_name
HAVING COUNT(e.emp_id) > 0
ORDER BY “平均工资” DESC;
部门名称 员工数量 最高工资 最低工资 平均工资 工资总额
———– ——– ——– ——– ——– ——–
技术部 3 9000 5000 7000 21000
销售部 2 8000 6000 7000 14000
— 案例:获取项目及其参与员工信息
SELECT
p.project_id AS “项目ID”,
p.project_name AS “项目名称”,
d.dept_name AS “所属部门”,
COUNT(e.emp_id) AS “参与员工数”,
LISTAGG(e.emp_name, ‘, ‘) WITHIN GROUP (ORDER BY e.emp_name) AS “参与员工”
FROM fgedu_projects p
INNER JOIN fgedu_departments d ON p.dept_id = d.dept_id
LEFT JOIN fgedu_emp_projects ep ON p.project_id = ep.project_id
LEFT JOIN fgedu_employees e ON ep.emp_id = e.emp_id
GROUP BY p.project_id, p.project_name, d.dept_name
ORDER BY p.project_id;
项目ID 项目名称 所属部门 参与员工数 参与员工
—— ———- ———- ———- ———-
1 项目A 技术部 2 张三, 王五
2 项目B 销售部 1 李四
3 项目C 技术部 2 张三, 王五
4.3 YashanDB连接优化实战案例
在生产环境中,优化连接查询提高性能:
— 优化前:未使用索引
EXPLAIN PLAN FOR
SELECT
e.emp_id, e.emp_name, d.dept_name, p.project_name
FROM fgedu_employees e
INNER JOIN fgedu_departments d ON e.dept_id = d.dept_id
INNER JOIN fgedu_emp_projects ep ON e.emp_id = ep.emp_id
INNER JOIN fgedu_projects p ON ep.project_id = p.project_id
WHERE e.salary > 6000;
— 执行计划显示全表扫描
— 优化后:创建索引
CREATE INDEX idx_fgedu_employees_salary ON fgedu_employees(salary);
— 执行优化后的查询
EXPLAIN PLAN FOR
SELECT
e.emp_id, e.emp_name, d.dept_name, p.project_name
FROM fgedu_employees e
INNER JOIN fgedu_departments d ON e.dept_id = d.dept_id
INNER JOIN fgedu_emp_projects ep ON e.emp_id = ep.emp_id
INNER JOIN fgedu_projects p ON ep.project_id = p.project_id
WHERE e.salary > 6000;
— 执行计划显示使用索引
— 案例:优化连接顺序
— 优化前:连接顺序不合理
SELECT
e.emp_id, e.emp_name, d.dept_name, p.project_name
FROM fgedu_emp_projects ep
INNER JOIN fgedu_employees e ON ep.emp_id = e.emp_id
INNER JOIN fgedu_departments d ON e.dept_id = d.dept_id
INNER JOIN fgedu_projects p ON ep.project_id = p.project_id
WHERE e.salary > 6000;
— 优化后:调整连接顺序
SELECT
e.emp_id, e.emp_name, d.dept_name, p.project_name
FROM fgedu_employees e
INNER JOIN fgedu_emp_projects ep ON e.emp_id = ep.emp_id
INNER JOIN fgedu_projects p ON ep.project_id = p.project_id
INNER JOIN fgedu_departments d ON e.dept_id = d.dept_id
WHERE e.salary > 6000;
Part05-风哥经验总结与分享
5.1 YashanDB多表连接使用经验
YashanDB多表连接使用经验总结:
- 选择合适的连接类型:根据业务需求选择合适的连接类型
- 优化连接条件:使用简单的连接条件,避免复杂的表达式
- 使用索引:为连接列创建索引,提高连接性能
- 限制返回行数:使用WHERE子句过滤数据,减少返回行数
- 优化连接顺序:合理安排连接顺序,提高查询性能
- 监控性能:定期监控连接查询的执行性能
5.2 YashanDB多表连接故障排除
## 1. 连接查询执行缓慢
– 症状:连接查询执行时间长
– 原因:缺少索引、全表扫描、复杂的连接操作
– 解决:创建适当的索引,优化查询结构,避免全表扫描
## 2. 索引失效
– 症状:连接查询没有使用索引
– 原因:索引列上使用了函数、类型不匹配、索引选择性低
– 解决:避免在索引列上使用函数,确保类型匹配,创建选择性高的索引
## 3. 连接顺序不合理
– 症状:连接查询执行计划不佳
– 原因:连接顺序不合理,导致中间结果集过大
– 解决:调整连接顺序,先连接小表,减少中间结果集
## 4. 连接条件不合适
– 症状:连接查询返回错误的结果或执行缓慢
– 原因:连接条件不正确或不优化
– 解决:检查连接条件,确保连接列类型匹配,使用简单的连接条件
## 5. 内存不足
– 症状:连接查询报错”ORA-04030: out of process memory”
– 原因:连接操作需要大量内存
– 解决:增加内存,优化连接查询,减少中间结果集
5.3 YashanDB多表连接使用建议
YashanDB多表连接使用建议:
- 使用索引:为连接列创建索引,提高连接性能
- 选择合适的连接类型:根据业务需求选择合适的连接类型
- 优化连接条件:使用简单的连接条件,避免复杂的表达式
- 限制返回行数:使用WHERE子句过滤数据,减少返回行数
- 监控性能:定期监控连接查询的执行性能,识别慢查询
- 分析执行计划:定期分析执行计划,优化连接路径
- 测试充分:在测试环境充分测试连接查询,确保性能满足要求
本文由风哥教程整理发布,仅用于学习测试使用,转载注明出处:http://www.fgedu.net.cn/10327.html
