优化 SQL 从两个连接表中获取数据(来自两个表的 user-from-id 和 user-to-id 消息的用户名)
Optimization SQL for getting data from two joined tables (usernames for user-from-id and user-to-id msgs from two tables)
我有 table "msgs" 用户之间的消息(他们的 ID):
+--------+-------------+------------+---------+---------+
| msg_id |user_from_id | user_to_id | message | room_id |
+--------+-------------+------------+---------+---------+
| 1 | 1 | 4 |Hello! | 2 |
| 2 | 1 | 5 |Hi there | 1 |
| 3 | 2 | 1 |CU soon | 2 |
| 4 | 3 | 7 |nice... | 1 |
+--------+-------------+------------+---------+---------+
我还有两个 table 用户名。
Table: 用户 1
+--------+----------+
|user_id |user_name |
+--------+----------+
| 5 | Ann |
| 6 | Sam |
| 7 | Michael |
+--------+----------+
Table: 用户 2
+--------+----------+
|user_id |user_name |
+--------+----------+
| 1 | John |
| 2 | Alice |
| 3 | Tom |
| 4 | Jane |
+--------+----------+
我需要为每一行中的两个用户 ID 获取用户名。每个用户 ID 可以在第一或第二 table 与用户名。
我写了这个 SQL 查询:
SELECT DISTINCT
m.msg_id,
m.user_from_id,
CASE WHEN c1.user_name IS NULL THEN c3.user_name ELSE c1.user_name END AS from_name,
m.user_to_id,
CASE WHEN c2.user_name IS NULL THEN c4.user_name ELSE c2.user_name END AS to_name,
m.message
FROM msgs m
LEFT JOIN users1 c1 ON c1.user_id=m.user_from_id
LEFT JOIN users1 c2 ON c2.user_id=m.user_to_id
LEFT JOIN users2 c3 ON c3.user_id=m.user_from_id
LEFT JOIN users2 c4 ON c4.user_id=m.user_to_id
WHERE m.room_id=1
LIMIT 0, 8
有效。
执行查询以获取没有用户名(没有任何连接)的原始数据大约需要 0.1 秒。但是仅加入一个用户名 table(仅限 user1 或 user2)就足以在大约 6.2 秒内获取此数据。 (加入一个 table)。我在这个 tables 中有很多行:msgs 中有 35K 行,user1 中有 0.5K 行,user2 中有 25K 行。
执行连接两个 table 的查询(包含所有这些数据)是不可能的。
如何优化这个查询?我只需要 user_ids 在第一个 "msgs" table.
中的用户名
有连接和没有连接的查询之间可能存在许多差异。我将假设 id
具有适当的索引——主键会自动执行。如果没有,那么检查一下。
显而易见的解决方案是将原始查询用作子查询:
SELECT m.msg_id, m.user_from_id,
(CASE WHEN c1.user_name IS NULL THEN c3.user_name ELSE c1.user_name
END) AS from_name,
m.user_to_id,
(CASE WHEN c2.user_name IS NULL THEN c4.user_name ELSE c2.user_name
END) AS to_name,
m.message
FROM (SELECT m.*
FROM msgs m
WHERE m.room_id = 1
LIMIT 0, 8
) m LEFT JOIN
users1 c1
ON c1.user_id = m.user_from_id LEFT JOIN
users1 c2
ON c2.user_id = m.user_to_id LEFT JOIN
users2 c3
ON c3.user_id = m.user_from_id LEFT JOIN
users2 c4
ON c4.user_id = m.user_to_id;
对于大多数数据结构,distinct
也是不必要的。
这也使得(合理的假设)user_id
在用户表中是唯一的。
另外,非常不鼓励在没有 ORDER BY
的情况下使用 LIMIT
。您获得的特定行是不确定的,并且可能会从一次执行更改为下一次执行。
我有 table "msgs" 用户之间的消息(他们的 ID):
+--------+-------------+------------+---------+---------+
| msg_id |user_from_id | user_to_id | message | room_id |
+--------+-------------+------------+---------+---------+
| 1 | 1 | 4 |Hello! | 2 |
| 2 | 1 | 5 |Hi there | 1 |
| 3 | 2 | 1 |CU soon | 2 |
| 4 | 3 | 7 |nice... | 1 |
+--------+-------------+------------+---------+---------+
我还有两个 table 用户名。
Table: 用户 1
+--------+----------+
|user_id |user_name |
+--------+----------+
| 5 | Ann |
| 6 | Sam |
| 7 | Michael |
+--------+----------+
Table: 用户 2
+--------+----------+
|user_id |user_name |
+--------+----------+
| 1 | John |
| 2 | Alice |
| 3 | Tom |
| 4 | Jane |
+--------+----------+
我需要为每一行中的两个用户 ID 获取用户名。每个用户 ID 可以在第一或第二 table 与用户名。
我写了这个 SQL 查询:
SELECT DISTINCT
m.msg_id,
m.user_from_id,
CASE WHEN c1.user_name IS NULL THEN c3.user_name ELSE c1.user_name END AS from_name,
m.user_to_id,
CASE WHEN c2.user_name IS NULL THEN c4.user_name ELSE c2.user_name END AS to_name,
m.message
FROM msgs m
LEFT JOIN users1 c1 ON c1.user_id=m.user_from_id
LEFT JOIN users1 c2 ON c2.user_id=m.user_to_id
LEFT JOIN users2 c3 ON c3.user_id=m.user_from_id
LEFT JOIN users2 c4 ON c4.user_id=m.user_to_id
WHERE m.room_id=1
LIMIT 0, 8
有效。 执行查询以获取没有用户名(没有任何连接)的原始数据大约需要 0.1 秒。但是仅加入一个用户名 table(仅限 user1 或 user2)就足以在大约 6.2 秒内获取此数据。 (加入一个 table)。我在这个 tables 中有很多行:msgs 中有 35K 行,user1 中有 0.5K 行,user2 中有 25K 行。 执行连接两个 table 的查询(包含所有这些数据)是不可能的。
如何优化这个查询?我只需要 user_ids 在第一个 "msgs" table.
中的用户名有连接和没有连接的查询之间可能存在许多差异。我将假设 id
具有适当的索引——主键会自动执行。如果没有,那么检查一下。
显而易见的解决方案是将原始查询用作子查询:
SELECT m.msg_id, m.user_from_id,
(CASE WHEN c1.user_name IS NULL THEN c3.user_name ELSE c1.user_name
END) AS from_name,
m.user_to_id,
(CASE WHEN c2.user_name IS NULL THEN c4.user_name ELSE c2.user_name
END) AS to_name,
m.message
FROM (SELECT m.*
FROM msgs m
WHERE m.room_id = 1
LIMIT 0, 8
) m LEFT JOIN
users1 c1
ON c1.user_id = m.user_from_id LEFT JOIN
users1 c2
ON c2.user_id = m.user_to_id LEFT JOIN
users2 c3
ON c3.user_id = m.user_from_id LEFT JOIN
users2 c4
ON c4.user_id = m.user_to_id;
对于大多数数据结构,distinct
也是不必要的。
这也使得(合理的假设)user_id
在用户表中是唯一的。
另外,非常不鼓励在没有 ORDER BY
的情况下使用 LIMIT
。您获得的特定行是不确定的,并且可能会从一次执行更改为下一次执行。