SQL return 结果 Table A,基于 Table B 的标准
SQL return results for Table A, based on criteria from Table B
我有 2 个 table 共享一对多关系。假设以下结构:
users users_metadata
------------- -------------
id | email id | user_id | type | score
一个用户可以有很多元数据。用户 table 有 100k 行,users_metadata table 有 300k 行。它可能会增长 10 倍,所以无论我写什么都需要针对大量数据进行优化。
我需要写一个 sql 声明 returns 只有通过元数据 table 中发现的几个不同评分条件的用户电子邮件。
// if type = 1 and if score > 75 then <1 point> else <0 points>
// if type = 2 and if score > 100 then <1 point> else <0 points>
// if type = 3 and if score > 0 then [-10 points] else <0 points>
// there are other types that we want to ignore in the score calculations
如果用户超过阈值(例如 >= 1 分),那么我希望该用户出现在结果集中,否则我希望忽略该用户。
我已经尝试用户存储 function/cursor 接受 user_id 并循环遍历元数据以找出要点,但结果执行速度非常慢(尽管它确实有效)。
目前我有这个,执行大约需要 1 到 3 秒。
SELECT u.id, u.email,
(
SELECT
SUM(
IF(k.type = 1, IF(k.score > 75, 1, 0), 0) +
IF(k.type = 2, IF(k.score > 100, 1, 0), 0) +
IF(k.type = 3, IF(k.score > 0, 1, -10), 0)
)
FROM user_metadata k WHERE k.user_id = u.id
) AS total
FROM users u GROUP BY u.id HAVING total IS NOT NULL;
我觉得在 10 倍时这会更慢。 1 到 3 秒的查询执行时间对于我已经需要的来说太慢了。
更理想的方法是什么?
如果我也为此使用 PHP 之类的语言,那么 运行 2 个查询,其中一个从 user_metadata
中获取 user_ids
,只有 passing
用户,然后再 SELECT 在该 ID 列表中的 WHERE IN 更好?
尝试使用 JOIN 而不是相关子查询。
SELECT u.id, u.email, t.total
FROM users AS u
JOIN (
SELECT user_id, SUM(CASE type
WHEN 1 THEN score > 75
WHEN 2 THEN score > 100
WHEN 3 THEN IF(k.score > 0, 1, -10)
END) AS total
FROM user_metadata
GROUP BY user_id
HAVING total >= 1
) AS t ON u.id = t.user_id
在子查询中进行分组和过滤使连接更小,这可以显着提高性能。
您也不需要在查询中使用 GROUP BY u.id
,因为那是您正在查询的 table 的主键;希望 MySQL 会优化它。
我有 2 个 table 共享一对多关系。假设以下结构:
users users_metadata
------------- -------------
id | email id | user_id | type | score
一个用户可以有很多元数据。用户 table 有 100k 行,users_metadata table 有 300k 行。它可能会增长 10 倍,所以无论我写什么都需要针对大量数据进行优化。
我需要写一个 sql 声明 returns 只有通过元数据 table 中发现的几个不同评分条件的用户电子邮件。
// if type = 1 and if score > 75 then <1 point> else <0 points>
// if type = 2 and if score > 100 then <1 point> else <0 points>
// if type = 3 and if score > 0 then [-10 points] else <0 points>
// there are other types that we want to ignore in the score calculations
如果用户超过阈值(例如 >= 1 分),那么我希望该用户出现在结果集中,否则我希望忽略该用户。
我已经尝试用户存储 function/cursor 接受 user_id 并循环遍历元数据以找出要点,但结果执行速度非常慢(尽管它确实有效)。
目前我有这个,执行大约需要 1 到 3 秒。
SELECT u.id, u.email,
(
SELECT
SUM(
IF(k.type = 1, IF(k.score > 75, 1, 0), 0) +
IF(k.type = 2, IF(k.score > 100, 1, 0), 0) +
IF(k.type = 3, IF(k.score > 0, 1, -10), 0)
)
FROM user_metadata k WHERE k.user_id = u.id
) AS total
FROM users u GROUP BY u.id HAVING total IS NOT NULL;
我觉得在 10 倍时这会更慢。 1 到 3 秒的查询执行时间对于我已经需要的来说太慢了。
更理想的方法是什么?
如果我也为此使用 PHP 之类的语言,那么 运行 2 个查询,其中一个从 user_metadata
中获取 user_ids
,只有 passing
用户,然后再 SELECT 在该 ID 列表中的 WHERE IN 更好?
尝试使用 JOIN 而不是相关子查询。
SELECT u.id, u.email, t.total
FROM users AS u
JOIN (
SELECT user_id, SUM(CASE type
WHEN 1 THEN score > 75
WHEN 2 THEN score > 100
WHEN 3 THEN IF(k.score > 0, 1, -10)
END) AS total
FROM user_metadata
GROUP BY user_id
HAVING total >= 1
) AS t ON u.id = t.user_id
在子查询中进行分组和过滤使连接更小,这可以显着提高性能。
您也不需要在查询中使用 GROUP BY u.id
,因为那是您正在查询的 table 的主键;希望 MySQL 会优化它。