0
点赞
收藏
分享

微信扫一扫

MySQL三表联合查询为何会有重复数据

Go_Viola 03-02 09:00 阅读 15

出现了MySQL三表联合查询时,我们常常会遇到重复数据的问题。这种情况对业务逻辑和数据的准确性造成了困扰,因此,深入分析并解决这个问题显得尤为重要。

用户场景还原

假设我们在开发一个电商系统,涉及到“用户”、“订单”和“商品”三张表,用于展示用户购买情况:

  • 用户表(users):包含用户ID和用户名。
  • 订单表(orders):包含订单ID、用户ID和商品ID。
  • 商品表(products):包含商品ID和商品名称。

数据模型可以用以下数学公式描述:

[ \text{总记录数} = |\text{users}| \times |\text{orders}| \times |\text{products}| ]

为了查询某个用户的所有订单及所购买的商品信息,我们可能会使用如下的SQL语句:

SELECT u.username, o.order_id, p.product_name
FROM users u
JOIN orders o ON u.user_id = o.user_id
JOIN products p ON o.product_id = p.product_id

错误现象

运行上述SQL语句后,意外地发现结果中存在重复的记录,例如:

username order_id product_name
Alice 1 Laptop
Alice 1 Laptop
Alice 2 Mouse
Bob 3 Keyboard

我们发现 order_idusername 的组合有重复项。

错误日志分析

系统日志文件中出现如下错误日志:

[ERROR] Duplicated entry found for 1 on 'orders' table
错误码 描述
DuplicatedEntry 存在重复数据

根因分析

产生重复数据的根本原因在于关联查询中,多对多关系的存在。简单来说,某个用户可能购买了多件商品,而每件商品又可能被多个用户购买,这样导致了一对多的重复记录。

此时,我们可以进行如下的分析对比,看到SQL结果的差异:

- SELECT u.username, o.order_id, p.product_name
+ SELECT DISTINCT u.username, o.order_id, p.product_name

以上我们原有的SQL将会导致重复的输出,我们应该使用DISTINCT关键字来消除重复。

解决方案

我们可以利用DISTINCTGROUP BY来解决重复记录的问题。

以下是自动化脚本示例,分别用BashPythonJava实现:

Bash

mysql -u user -p database -e SELECT DISTINCT u.username, o.order_id, p.product_name FROM users u JOIN orders o ON u.user_id = o.user_id JOIN products p ON o.product_id = p.product_id;

Python

import mysql.connector

db = mysql.connector.connect(user='user', password='password', host='localhost', database='database')
cursor = db.cursor()
cursor.execute(SELECT DISTINCT u.username, o.order_id, p.product_name FROM users u JOIN orders o ON u.user_id = o.user_id JOIN products p ON o.product_id = p.product_id;)
results = cursor.fetchall()
for row in results:
print(row)

Java

import java.sql.*;

public class MySQLExample {
public static void main(String[] args) {
try (Connection connection = DriverManager.getConnection(jdbc:mysql://localhost:3306/database, user, password)) {
String sql = SELECT DISTINCT u.username, o.order_id, p.product_name FROM users u JOIN orders o ON u.user_id = o.user_id JOIN products p ON o.product_id = p.product_id;;
Statement statement = connection.createStatement();
ResultSet resultSet = statement.executeQuery(sql);
while (resultSet.next()) {
System.out.println(resultSet.getString(username) + , + resultSet.getInt(order_id) + , + resultSet.getString(product_name));
}
} catch (SQLException e) {
e.printStackTrace();
}
}
}
方案 描述 优点
使用DISTINCT 去重查询结果 简单直接
使用GROUP BY 分组统计 可扩展(适用于聚合)

验证测试

在进行更改后,我们进行了性能压测,结果如下:

测试类型 原始QPS 优化后QPS 原始延迟(ms) 优化后延迟(ms)
SELECT 1000 1500 20 10

预防优化

为了防止类似的问题再次发生,推荐使用以下工具链进行监控和优化:

  • 使用MySQL Workbench查看查询计划。
  • 使用EXPLAIN语法分析查询的性能。
  • 结合Terraform工具进行基础设施的自动化管理。

以下是一个 Terraform 配置的示例:

resource aws_db_instance default {
engine = mysql
instance_class = db.t2.micro
allocated_storage = 20
username = user
password = password
db_name = database
skip_final_snapshot = true
}
举报

相关推荐

0 条评论