我的表“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 |
+--------+-------------+------------+---------+---------+
我还有两个用户名表 表:user1
+--------+----------+
|user_id |user_name |
+--------+----------+
| 5 | Ann |
| 6 | Sam |
| 7 | Michael |
+--------+----------+
表:user2
+--------+----------+
|user_id |user_name |
+--------+----------+
| 1 | John |
| 2 | Alice |
| 3 | Tom |
| 4 | Jane |
+--------+----------+
我需要在每一行中获取两个用户ID的用户名。每个user-id都可以在带有用户名的第一个或第二个表中。
我写了这个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秒。但仅加入一个用户名表(仅限user1或user2)就足以在约6.2秒内获取此数据。 (加入一个表)。我在这个表中有很多行:msgs中35K行,user1中0.5K,user2中25K。 用连接两个表(包含所有这些数据)执行查询是不可能的。
如何优化此查询?我只需要在第一个“msgs”表中使用user_ids的用户名。
答案 0 :(得分:1)
有和没有连接的查询之间可能存在许多差异。我将假设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
在用户表中是唯一的。
此外,强烈建议不要LIMIT
使用ORDER BY
。您获得的特定行是不确定的,可能会从一次执行更改为下一次执行。