改进查询以根据没有联合的值连接其他表
Improve query to join other tables depending on value without union
我有一个 table 包含以下数据:
+-----------------+--------------+----------------------+------------+--------------------+-----------+------+---------+---------+-----+------------------------+---------------------+
| notification_id | from_user_id | from_user_auth_level | to_user_id | to_user_auth_level | status_id | type | subject | message | url | timestamp_inserted_utc | timestamp_read_utc |
+-----------------+--------------+----------------------+------------+--------------------+-----------+------+---------+---------+-----+------------------------+---------------------+
| 1 | NULL | NULL | 1 | 1 | 0 | 2 | test | test | url | 2010-10-10 00:00:00 | 2011-10-10 00:00:00 |
| 2 | 2 | 5 | 1 | 1 | 0 | 2 | test | test | url | 2010-10-10 00:00:00 | 2011-10-10 00:00:00 |
| 3 | 3 | 5 | 1 | 1 | 0 | 2 | test | test | url | 2010-10-10 00:00:00 | 2011-10-10 00:00:00 |
| 4 | 2295 | 4 | 1 | 1 | 0 | 2 | test | test | url | 2010-10-10 00:00:00 | 2011-10-10 00:00:00 |
| 5 | 10 | 1 | 1 | 1 | 0 | 2 | test | test | url | 2010-10-10 00:00:00 | 2011-10-10 00:00:00 |
+-----------------+--------------+----------------------+------------+--------------------+-----------+------+---------+---------+-----+------------------------+---------------------+
然后我还有其他一些 table,例如 'users'、'companies'、'organizations'、...等等
我需要能够获取每个通知的用户名、性别和图像(基于 from_user_id 和 from_user_auth_level)。
但问题在于,此信息位于不同的位置,具体取决于 user_auth_level 是什么。
例如:如果我的用户是 "regular" 用户,他的 auth_level 将是 1。图像将驻留在我的 "users" table 中,并且性别适用。
但是如果用户有auth_level == 5,就说明他是一个组织。在这种情况下,性别不适用,图片位于 "organization" table,这需要通过用户链接到 user_roles,然后再链接到组织。
这适用于每种用户类型,他们都需要不同的加入。
我已经创建了一个有效的查询,但是它到处都使用 UNION,而且我了解到出于性能原因,它并不是最好的使用方式,所以我希望有人可以指导我改进这个查询的性能头脑:
SELECT n.*, NULL as username, NULL as gender, NULL as picture
FROM notification as n
WHERE n.from_user_auth_level IS NULL
AND n.to_user_id = $userid
UNION
SELECT n.*, u.username, u.gender as gender, u.profile_picture as picture
FROM notification as n
LEFT JOIN users AS u ON n.from_user_id = u.user_id
WHERE n.from_user_auth_level = 1
AND n.to_user_id = $userid
UNION
SELECT n.*, u.username, NULL as gender, c.logo as picture
FROM notification as n
LEFT JOIN users AS u ON n.from_user_id = u.user_id
LEFT JOIN user_companies AS uc on u.user_id = uc.user_id
LEFT JOIN company as c on uc.company_id = c.company_id
WHERE n.from_user_auth_level = 4
AND n.to_user_id = $userid
UNION
SELECT n.*, u.username, NULL as gender, o.logo as picture
FROM notification as n
LEFT JOIN users AS u ON n.from_user_id = u.user_id
LEFT JOIN user_roles as ur on u.user_id = ur.user_id
LEFT JOIN organization as o on ur.org_id = o.org_id
WHERE n.from_user_auth_level = 5
AND n.to_user_id = $userid
UNION
SELECT n.*, u.username, NULL as gender, o.logo as picture
FROM notification as n
LEFT JOIN users AS u ON n.from_user_id = u.user_id
LEFT JOIN user_roles as ur on u.user_id = ur.user_id
LEFT JOIN organization as o on ur.org_id = o.org_id
WHERE n.from_user_auth_level = 7
AND n.to_user_id = $userid
UNION
SELECT n.*, u.username, NULL as gender, NULL as picture
FROM notification as n
LEFT JOIN users AS u ON n.from_user_id = u.user_id
WHERE n.from_user_auth_level = 9
AND n.to_user_id = $userid"
得到这个结果后,我使用 PHP 根据 timestamp_inserted_utc 对结果进行排序,因为使用 UNION 不可能得到正确的结果。
我将使用通知 table 作为基础并使用条件外连接作为:
select
n.*,t1.gender, t2.orgNo
from
notifications n
left outer join table1 t1 on (n.auth=1 and more join)
left outer join table2 t2 on (n.auth=2 and more..)
您将有更多的列,但它们的名称是有意义的,您可以在应用程序级别合并。
建议索引(大部分为"covering"):
n: (from_user_auth_level, to_user_id, from_user_id)
u: (user_id, username, profile_picture, gender)
o: (org_id, logo)
ur: (org_id, user_id)
c: (company_id, logo)
uc: (company_id, user_id)
(他们甚至可以加快 Teson 的回答速度。)
我有一个 table 包含以下数据:
+-----------------+--------------+----------------------+------------+--------------------+-----------+------+---------+---------+-----+------------------------+---------------------+
| notification_id | from_user_id | from_user_auth_level | to_user_id | to_user_auth_level | status_id | type | subject | message | url | timestamp_inserted_utc | timestamp_read_utc |
+-----------------+--------------+----------------------+------------+--------------------+-----------+------+---------+---------+-----+------------------------+---------------------+
| 1 | NULL | NULL | 1 | 1 | 0 | 2 | test | test | url | 2010-10-10 00:00:00 | 2011-10-10 00:00:00 |
| 2 | 2 | 5 | 1 | 1 | 0 | 2 | test | test | url | 2010-10-10 00:00:00 | 2011-10-10 00:00:00 |
| 3 | 3 | 5 | 1 | 1 | 0 | 2 | test | test | url | 2010-10-10 00:00:00 | 2011-10-10 00:00:00 |
| 4 | 2295 | 4 | 1 | 1 | 0 | 2 | test | test | url | 2010-10-10 00:00:00 | 2011-10-10 00:00:00 |
| 5 | 10 | 1 | 1 | 1 | 0 | 2 | test | test | url | 2010-10-10 00:00:00 | 2011-10-10 00:00:00 |
+-----------------+--------------+----------------------+------------+--------------------+-----------+------+---------+---------+-----+------------------------+---------------------+
然后我还有其他一些 table,例如 'users'、'companies'、'organizations'、...等等
我需要能够获取每个通知的用户名、性别和图像(基于 from_user_id 和 from_user_auth_level)。
但问题在于,此信息位于不同的位置,具体取决于 user_auth_level 是什么。
例如:如果我的用户是 "regular" 用户,他的 auth_level 将是 1。图像将驻留在我的 "users" table 中,并且性别适用。 但是如果用户有auth_level == 5,就说明他是一个组织。在这种情况下,性别不适用,图片位于 "organization" table,这需要通过用户链接到 user_roles,然后再链接到组织。
这适用于每种用户类型,他们都需要不同的加入。
我已经创建了一个有效的查询,但是它到处都使用 UNION,而且我了解到出于性能原因,它并不是最好的使用方式,所以我希望有人可以指导我改进这个查询的性能头脑:
SELECT n.*, NULL as username, NULL as gender, NULL as picture
FROM notification as n
WHERE n.from_user_auth_level IS NULL
AND n.to_user_id = $userid
UNION
SELECT n.*, u.username, u.gender as gender, u.profile_picture as picture
FROM notification as n
LEFT JOIN users AS u ON n.from_user_id = u.user_id
WHERE n.from_user_auth_level = 1
AND n.to_user_id = $userid
UNION
SELECT n.*, u.username, NULL as gender, c.logo as picture
FROM notification as n
LEFT JOIN users AS u ON n.from_user_id = u.user_id
LEFT JOIN user_companies AS uc on u.user_id = uc.user_id
LEFT JOIN company as c on uc.company_id = c.company_id
WHERE n.from_user_auth_level = 4
AND n.to_user_id = $userid
UNION
SELECT n.*, u.username, NULL as gender, o.logo as picture
FROM notification as n
LEFT JOIN users AS u ON n.from_user_id = u.user_id
LEFT JOIN user_roles as ur on u.user_id = ur.user_id
LEFT JOIN organization as o on ur.org_id = o.org_id
WHERE n.from_user_auth_level = 5
AND n.to_user_id = $userid
UNION
SELECT n.*, u.username, NULL as gender, o.logo as picture
FROM notification as n
LEFT JOIN users AS u ON n.from_user_id = u.user_id
LEFT JOIN user_roles as ur on u.user_id = ur.user_id
LEFT JOIN organization as o on ur.org_id = o.org_id
WHERE n.from_user_auth_level = 7
AND n.to_user_id = $userid
UNION
SELECT n.*, u.username, NULL as gender, NULL as picture
FROM notification as n
LEFT JOIN users AS u ON n.from_user_id = u.user_id
WHERE n.from_user_auth_level = 9
AND n.to_user_id = $userid"
得到这个结果后,我使用 PHP 根据 timestamp_inserted_utc 对结果进行排序,因为使用 UNION 不可能得到正确的结果。
我将使用通知 table 作为基础并使用条件外连接作为:
select
n.*,t1.gender, t2.orgNo
from
notifications n
left outer join table1 t1 on (n.auth=1 and more join)
left outer join table2 t2 on (n.auth=2 and more..)
您将有更多的列,但它们的名称是有意义的,您可以在应用程序级别合并。
建议索引(大部分为"covering"):
n: (from_user_auth_level, to_user_id, from_user_id)
u: (user_id, username, profile_picture, gender)
o: (org_id, logo)
ur: (org_id, user_id)
c: (company_id, logo)
uc: (company_id, user_id)
(他们甚至可以加快 Teson 的回答速度。)