sql中用JOIN USING 简化JOIN ON

本文详细介绍了Mysql中联接SQL语句中ON子句与USING语法的区别与使用场景,通过实例展示了如何利用USING语法简化ON语法,提升查询效率。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Mysql 中联接SQL语句中,ON子句的语法格式为:table1.column_name = table2.column_name。
当模式设计对联接表的列采用了相同的命名样式时,就可以使用 USING 语法来简化 ON 语法,格式为:USING(column_name)。
例如:
[sql]
SELECT f.color, c.is_primary, c.is_dark, c.is_rainbow  
FROM flags f    www.2cto.com  
INNER JOIN color c ON f.color = c.color  
WHERE f.country = 'China';  
等价于
[sql]
SELECT f.color, c.is_primary, c.is_dark, c.is_rainbow  
FROM flags f  
INNER JOIN color c USING(color)  
WHERE f.country = 'China';  


<think>我们正在讨论如何通过EXPLAIN结果分析JOIN查询的性能瓶颈。根据引用[2][3][4],EXPLAIN是MySQL中用于分析SQL执行计划的关键工具。以下是针对JOIN操作性能瓶颈分析的详细步骤: ### 一、核心性能瓶颈定位指标 在EXPLAIN结果中,重点关注以下字段: | **字段** | **关键值** | **性能瓶颈指示** | |------------------|-------------------------------|-------------------------------------------------------------------------------| | **type** | `ALL` | 全表扫描(被驱动表无索引)[^3] | | | `index` | 全索引扫描(效率较低) | | **key** | `NULL` | 未使用索引 | | **possible_keys**| 有值但key为NULL | 索引失效 | | **rows** | 数值过大(>10万) | 扫描行数过多 | | **Extra** | `Using join buffer` | 使用Block Nested-Loop Join(需优化)[^3] | | | `Using temporary` | 使用临时表(大表JOIN危险信号) | | | `Using filesort` | 额外排序操作 | ### 二、JOIN瓶颈分析实战步骤 #### 步骤1:查看驱动表选择 ```sql EXPLAIN SELECT * FROM orders o JOIN customers c ON o.customer_id = c.id; ``` - **驱动表判断**:EXPLAIN结果中**首行**为驱动表 - **优化原则**:驱动表应为小表(rows值最小) ```markdown | id | select_type | table | type | rows | |----|-------------|-------|------|---------| | 1 | SIMPLE | c | ALL | 1000 | <-- 驱动表 | 1 | SIMPLE | o | ref | 1000000 | ``` > 💡 此处驱动表`customers`仅1000行,符合小表驱动原则 #### 步骤2:检查被驱动表索引 - **致命问题**:若被驱动表的`type`为`ALL`且`key`为`NULL` ```markdown | id | select_type | table | type | key | rows | | 1 | SIMPLE | o | ALL | NULL | 1000000 | <-- 被驱动表无索引 ``` **解决方案**: ```sql ALTER TABLE orders ADD INDEX idx_customer (customer_id); ``` #### 步骤3:分析连接算法 - **Extra字段**: - `Using join buffer (Block Nested Loop)` → BNLJ算法(性能差)[^3] - `NULL` → Index Nested-Loop Join(理想状态) - **优化案例**: ```markdown # 优化前: | table | type | key | Extra | | o | ALL | NULL | Using join buffer (BNL) | # 添加索引后: | table | type | ref | key | Extra | | o | ref | c.id | idx_customer | NULL | <-- 索引生效 ``` #### 步骤4:评估扫描行数 - **rows乘积法则**:总扫描行数 ≈ 驱动表rows × 被驱动表rows ```markdown | id | table | rows | | 1 | c | 1000 | | 1 | o | 10 | <-- 通过索引后仅扫描10行/次 总扫描行数 = 1000 + 1000*10 = 11,000行(高效) ``` 对比无索引情况: ```markdown 总扫描行数 = 1000 + 1000*1,000,000 = 1,001,000,000行(灾难性) ``` ### 三、高级瓶颈诊断技巧 #### 1. 索引失效分析 - **场景**:`possible_keys`有值但`key`为`NULL` ```sql -- 示例:类型转换导致索引失效 SELECT * FROM users u JOIN orders o ON u.id = o.user_id WHERE u.phone = 13800138000; -- phone是varchar类型 ``` **EXPLAIN结果**: ```markdown | table | type | possible_keys | key | Extra | | u | ALL | idx_phone | NULL | Using where | ``` **原因**:数字比较导致索引失效 #### 2. 多表JOIN顺序优化 - **ID相同**:执行顺序从上到下 ```markdown | id | table | rows | | 1 | t1 | 10 | | 1 | t2 | 100 | <-- 驱动表t1扫描10行,t2作为被驱动表 | 1 | t3 | 1000 | <-- 前两表JOIN结果作为驱动表 ``` **优化点**:确保中间结果集最小 #### 3. 临时表与文件排序 - **危险信号**: ```markdown | Extra | |----------------------------------------| | Using temporary; Using filesort | <-- 需内存排序 ``` **优化方案**: ```sql -- 增加排序字段索引 CREATE INDEX idx_sort ON orders(order_date, amount); ``` ### 四、性能优化决策树 ```mermaid graph TD A[EXPLAIN分析] --> B{驱动表rows是否最小?} B -->|否| C[调整JOIN顺序或使用STRAIGHT_JOIN] B -->|是| D{被驱动表是否有索引?} D -->|否| E[为连接字段添加索引] D -->|是| F{Extra是否有BNL?} F -->|是| G[检查索引有效性/增大join_buffer] F -->|否| H{是否有Using temporary/filesort?} H -->|是| I[优化ORDER BY/GROUP BY] H -->|否| J[已达最优状态] ``` ### 五、真实案例优化对比 **场景**:用户表(50万) JOIN 订单表(3000万) ```sql -- 原始查询(无索引) EXPLAIN SELECT * FROM users u JOIN orders o ON u.id = o.user_id; ``` **优化前**: | table | type | rows | Extra | |-------|------|----------|------------------------| | u | ALL | 500,000 | NULL | | o | ALL | 29,000,000 | Using join buffer (BNL)| **问题诊断**: 1. 驱动表`users`过大(50万行) 2. 被驱动表`orders`无索引 → 全表扫描3000万行 3. 使用BNLJ算法 → 总扫描行数$5\times10^5 \times 3\times10^7 = 1.5\times10^{13}$ **优化措施**: 1. 添加索引: ```sql ALTER TABLE orders ADD INDEX idx_user (user_id); ``` 2. 使用小表驱动(根据数据特征调整): ```sql -- 假设活跃用户仅10万 SELECT * FROM ( SELECT * FROM users WHERE is_active=1 ) u_active JOIN orders o ON u_active.id = o.user_id; ``` **优化后**: | table | type | rows | Extra | |----------|------|--------|--------| | u_active | ref | 100,000| NULL | | o | ref | 30 | NULL | <-- 索引命中选择性高 **性能提升**:从超时(>300s) → 0.8秒 > 📌 **核心要点**:通过EXPLAIN识别`type=ALL`和`Using join buffer`是解决JOIN性能瓶颈的关键突破口[^2][^3][^4]。 §§相关问题§§ 1. 如何强制MySQL使用特定JOIN顺序? 2. `Using filesort`是否一定表示性能问题? 3. MySQL 8.0中EXPLAIN ANALYZE的使用方法? 4. 如何解读EXPLAIN中的filtered字段? 5. 大表JOIN时出现`Using temporary`该如何优化?</think>## 通过EXPLAIN结果分析JOIN性能瓶颈的方法 MySQL的EXPLAIN命令是诊断JOIN性能问题的核心工具。以下是关键分析步骤和指标解读: --- ### 一、核心性能瓶颈定位指标 | **EXPLAIN字段** | **关键值** | **性能瓶颈指示** | |-----------------|------------------------|-------------------------------------------------------------------------------| | **type** | `ALL` | 全表扫描(被驱动表无索引)[^3] | | | `index` | 全索引扫描(效率较低) | | **key** | `NULL` | 未使用索引 | | **possible_keys**| 有值但key为NULL | 索引失效 | | **rows** | 数值过大(>10万) | 扫描行数过多 | | **Extra** | `Using join buffer` | 使用Block Nested-Loop Join(需优化)[^3] | | | `Using temporary` | 使用临时表(大表JOIN危险信号) | | | `Using filesort` | 额外排序操作 | --- ### 二、JOIN瓶颈分析四步法 #### 步骤1:检查驱动表选择 ```sql EXPLAIN SELECT * FROM orders o JOIN customers c ON o.customer_id = c.id; ``` - **驱动表判断**:EXPLAIN结果中**首行**为驱动表 - **优化原则**:驱动表应为小表(rows值最小) ```markdown | id | select_type | table | type | rows | | 1 | SIMPLE | c | ALL | 1000 | <-- 驱动表 | 1 | SIMPLE | o | ref | 1000000 | ``` > 💡 此处驱动表`customers`仅1000行,符合小表驱动原则 #### 步骤2:验证被驱动表索引 - **致命问题**:若被驱动表的`type`为`ALL`且`key`为`NULL` ```markdown | id | table | type | key | rows | | 1 | o | ALL | NULL | 1000000 | <-- 被驱动表无索引 ``` **解决方案**: ```sql ALTER TABLE orders ADD INDEX idx_customer (customer_id); ``` #### 步骤3:分析连接算法 - **Extra字段**: - `Using join buffer (Block Nested Loop)` → BNLJ算法(性能差)[^3] - `NULL` → Index Nested-Loop Join(理想状态) - **优化案例**: ```markdown # 优化前: | table | type | key | Extra | | o | ALL | NULL | Using join buffer (BNL) | # 添加索引后: | table | type | ref | key | Extra | | o | ref | c.id | idx_customer | NULL | <-- 索引生效 ``` #### 步骤4:评估扫描行数 - **rows乘积法则**:总扫描行数 ≈ 驱动表rows × 被驱动表rows ```markdown | id | table | rows | | 1 | c | 1000 | | 1 | o | 10 | <-- 通过索引后仅扫描10行/次 总扫描行数 = 1000 + 1000*10 = 11,000行(高效) ``` 对比无索引情况: ```markdown 总扫描行数 = 1000 + 1000*1,000,000 = 1,001,000,000行(灾难性) ``` --- ### 三、高级瓶颈诊断技巧 #### 1. 索引失效分析 - **场景**:`possible_keys`有值但`key`为`NULL` ```sql -- 类型转换导致索引失效 SELECT * FROM users u JOIN orders o ON u.id = o.user_id WHERE u.phone = 13800138000; -- phone是varchar类型 ``` **EXPLAIN结果**: ```markdown | table | type | possible_keys | key | Extra | | u | ALL | idx_phone | NULL | Using where | ``` #### 2. 多表JOIN顺序优化 - **ID相同**:执行顺序从上到下 ```markdown | id | table | rows | | 1 | t1 | 10 | | 1 | t2 | 100 | <-- 驱动表t1扫描10行,t2作为被驱动表 | 1 | t3 | 1000 | <-- 前两表JOIN结果作为驱动表 ``` **优化点**:确保中间结果集最小 #### 3. 临时表与文件排序 - **危险信号**: ```markdown | Extra | |----------------------------------------| | Using temporary; Using filesort | <-- 需内存排序 ``` **优化方案**: ```sql CREATE INDEX idx_sort ON orders(order_date, amount); ``` --- ### 四、性能优化决策树 ```mermaid graph TD A[EXPLAIN分析] --> B{驱动表rows是否最小?} B -->|否| C[调整JOIN顺序或使用STRAIGHT_JOIN] B -->|是| D{被驱动表是否有索引?} D -->|否| E[为连接字段添加索引] D -->|是| F{Extra是否有BNL?} F -->|是| G[检查索引有效性/增大join_buffer] F -->|否| H{是否有Using temporary/filesort?} H -->|是| I[优化ORDER BY/GROUP BY] H -->|否| J[已达最优状态] ``` --- ### 五、真实案例优化对比 **场景**:用户表(50万) JOIN 订单表(3000万) ```sql -- 原始查询(无索引) EXPLAIN SELECT * FROM users u JOIN orders o ON u.id = o.user_id; ``` **优化前**: | table | type | rows | Extra | |-------|------|----------|------------------------| | u | ALL | 500,000 | NULL | | o | ALL | 29,000,000 | Using join buffer (BNL)| **优化后**: ```sql ALTER TABLE orders ADD INDEX idx_user (user_id); SELECT * FROM ( SELECT * FROM users WHERE is_active=1 -- 减小驱动表 ) u_active JOIN orders o ON u_active.id = o.user_id; ``` | table | type | rows | Extra | |----------|------|--------|--------| | u_active | ref | 100,000| NULL | | o | ref | 30 | NULL | <-- 索引命中选择性高 **性能提升**:从超时(>300s) → 0.8秒 > 📌 **核心要点**:通过EXPLAIN识别`type=ALL`和`Using join buffer`是解决JOIN性能瓶颈的关键突破口[^2][^3][^4]。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值