MySQL:如何选择和处理;n到n“;与性能相关的数据
作业:MySQL:如何选择和处理;n到n“;与性能相关的数据,mysql,sql,performance,select,relationship,Mysql,Sql,Performance,Select,Relationship,作业: 我需要选择具有多对多关系的数据,并搜索具有良好性能的解决方案。我目前有两个可行的解决方案(见下文) 示例/说明: 比赛是由组织推动的。一项竞赛可以没有、一个或多个组织作为发起人。我只需要在每次比赛的结果与身份证名单的推广人只有一次 数据结构: -表“竞赛”:(id、名称) -表“组织”:(id、名称) -表“竞争组织”:(竞争ID、组织ID) 所需结果: |id |姓名|发起人|名单| |1 |欧洲冠军联赛| 1241 | |2 |国际足联世界杯1240 | |3 |国际足联世界杯预赛-
我需要选择具有多对多关系的数据,并搜索具有良好性能的解决方案。我目前有两个可行的解决方案(见下文) 示例/说明:
比赛是由组织推动的。一项竞赛可以没有、一个或多个组织作为发起人。我只需要在每次比赛的结果与身份证名单的推广人只有一次 数据结构:
-表“竞赛”:(id、名称)
-表“组织”:(id、名称)
-表“竞争组织”:(竞争ID、组织ID)
所需结果:
|id |姓名|发起人|名单|
|1 |欧洲冠军联赛| 1241 |
|2 |国际足联世界杯1240 |
|3 |国际足联世界杯预赛-非洲1240、1242 |
开发平台:冷聚变 数据库:MySQL 基于给定答案的附加注释:
-我的问题的主要意图是找到一种比过去更好地处理此类关系的方法。比赛只是我需要的一个例子。
-我试图让它更简单,也许我忽略了一个事实太多。在我的申请中,我还需要组织名称。出于这个原因,我加入了Organiaton表。
-一场比赛的相关信息比我在本例中描述的要多。我的应用程序中的查询使用多个到其他表的联接
解决方案1:
-查询选择比赛数据
-循环结果
-将每条记录存储在循环内的数组中
-用于为结果/循环中的每条记录选择发起人的附加查询
-将带有另一个查询循环的启动程序id添加到数组中
主查询:
SELECT competition.id, competition.name
FROM competition
WHERE ...
SELECT DISTINCT organisation.id
FROM organisation
INNER JOIN competition_organisation
ON competition_organisation.organisationID = organisation.id
WHERE competition_organisation.competitionID = competition.id[currentrow]#
循环内的附加启动子查询:
SELECT competition.id, competition.name
FROM competition
WHERE ...
SELECT DISTINCT organisation.id
FROM organisation
INNER JOIN competition_organisation
ON competition_organisation.organisationID = organisation.id
WHERE competition_organisation.competitionID = competition.id[currentrow]#
解决方案2:
-仅对子选择使用一个查询
-循环结果
-将每条记录存储在循环内的数组中
SELECT competition.id, competition.name,
(
SELECT CONVERT(GROUP_CONCAT(organisation.id SEPARATOR ', ') USING utf8)
FROM organisation
WHERE organisation.id in
(
SELECT DISTINCT competition_organisation.organisationID
FROM competition_organisation
WHERE competition_organisation.competitionID = competition.id
)
) AS promoter_list
FROM competition
WHERE ...
解决方案3(由Spencer7593提出):
SELECT c.id,
c.name,
CONVERT(GROUP_CONCAT(DISTINCT o.id ORDER BY o.id) USING utf8) AS promoter_id_list,
CONVERT(GROUP_CONCAT(DISTINCT o.name ORDER BY o.id) USING utf8) AS promoter_list
FROM competition c
LEFT JOIN competition_organisation c_o ON c_o.competitionID = c.id
LEFT JOIN organisation o ON o.id = c_o.organisationID
GROUP BY c.id, c.name
SELECT id, name,
( SELECT CONVERT(GROUP_CONCAT(organisationID SEPARATOR ', ') USING utf8)
FROM competition_organisation
WHERE competitionID = c.id
) AS promoter_id_list,
( SELECT CONVERT(GROUP_CONCAT(organisation.name SEPARATOR ', ') USING utf8)
FROM competition
left join competition_organisation on competition_organisation.competitionID = competition.id
left join organisationen on organisationen.id = competition_organisation.organisationID
WHERE competitionID = c.id
) AS promoter_list
FROM competition AS c
(我稍微更改了代码并添加了组织名称)解决方案4(由Thorsten Kettner提出,由Rick James优化):
SELECT c.id,
c.name,
CONVERT(GROUP_CONCAT(DISTINCT o.id ORDER BY o.id) USING utf8) AS promoter_id_list,
CONVERT(GROUP_CONCAT(DISTINCT o.name ORDER BY o.id) USING utf8) AS promoter_list
FROM competition c
LEFT JOIN competition_organisation c_o ON c_o.competitionID = c.id
LEFT JOIN organisation o ON o.id = c_o.organisationID
GROUP BY c.id, c.name
SELECT id, name,
( SELECT CONVERT(GROUP_CONCAT(organisationID SEPARATOR ', ') USING utf8)
FROM competition_organisation
WHERE competitionID = c.id
) AS promoter_id_list,
( SELECT CONVERT(GROUP_CONCAT(organisation.name SEPARATOR ', ') USING utf8)
FROM competition
left join competition_organisation on competition_organisation.competitionID = competition.id
left join organisationen on organisationen.id = competition_organisation.organisationID
WHERE competitionID = c.id
) AS promoter_list
FROM competition AS c
(还添加了组织名称,希望方式正确)
性能比较:
SELECT c.id,
c.name,
CONVERT(GROUP_CONCAT(DISTINCT o.id ORDER BY o.id) USING utf8) AS promoter_id_list,
CONVERT(GROUP_CONCAT(DISTINCT o.name ORDER BY o.id) USING utf8) AS promoter_list
FROM competition c
LEFT JOIN competition_organisation c_o ON c_o.competitionID = c.id
LEFT JOIN organisation o ON o.id = c_o.organisationID
GROUP BY c.id, c.name
SELECT id, name,
( SELECT CONVERT(GROUP_CONCAT(organisationID SEPARATOR ', ') USING utf8)
FROM competition_organisation
WHERE competitionID = c.id
) AS promoter_id_list,
( SELECT CONVERT(GROUP_CONCAT(organisation.name SEPARATOR ', ') USING utf8)
FROM competition
left join competition_organisation on competition_organisation.competitionID = competition.id
left join organisationen on organisationen.id = competition_organisation.organisationID
WHERE competitionID = c.id
) AS promoter_list
FROM competition AS c
解决方案1-100条记录:~30ms+(100 x~1ms)=~130ms解决方案1-1000条记录:~70ms+(1000x~1ms)=~1070ms 解决方案2-100条记录:~5500ms
解决方案2-1000条记录:~48000ms
解决方案3-100条记录:~120ms
解决方案3-1000条记录:~210ms
解决方案4-100条记录:~110ms
解决方案4-1000条记录:~200ms
如您所见,解决方案2的性能很差
- 是否有优化solution 2查询以显著提高性能的选项
- 有没有我没有想到的替代方案
- 或者我应该继续使用解决方案1
结论:
SELECT c.id,
c.name,
CONVERT(GROUP_CONCAT(DISTINCT o.id ORDER BY o.id) USING utf8) AS promoter_id_list,
CONVERT(GROUP_CONCAT(DISTINCT o.name ORDER BY o.id) USING utf8) AS promoter_list
FROM competition c
LEFT JOIN competition_organisation c_o ON c_o.competitionID = c.id
LEFT JOIN organisation o ON o.id = c_o.organisationID
GROUP BY c.id, c.name
SELECT id, name,
( SELECT CONVERT(GROUP_CONCAT(organisationID SEPARATOR ', ') USING utf8)
FROM competition_organisation
WHERE competitionID = c.id
) AS promoter_id_list,
( SELECT CONVERT(GROUP_CONCAT(organisation.name SEPARATOR ', ') USING utf8)
FROM competition
left join competition_organisation on competition_organisation.competitionID = competition.id
left join organisationen on organisationen.id = competition_organisation.organisationID
WHERE competitionID = c.id
) AS promoter_list
FROM competition AS c
我决定采用斯宾塞的解决方案3。3和4的性能几乎相同。但是3的代码更简单,并且与我现有的查询完全匹配,特别是与它们的左连接
我对结果非常满意。性能已经大大提高,将来我需要更少的代码/文件
非常感谢您的帮助 单个查询几乎总是比过程快。否则,这可能表示查询中存在缺陷
DISTINCT
不属于子查询中的。如何查找数据应由DBMS决定。
子句中的也应该是非相关的。如果您想要或需要相关的内容,请使用EXISTS
。那么,你为什么要加入表组织
?你不需要那张桌子上的任何东西
select c.id, c.name, co.promoter_list
from competition c
left join
(
select
competitionid,
group_concat(organisationid separator ', ') as promoter_list
from competition_organisation
group by competitionid
) co on co.competitionid = c.id;
解决方案3:
使用外部连接操作和MySQL特定的GROUP\u CONCAT
aggregate函数返回以逗号分隔的OrganizationID值列表
-- SHOW VARIABLES LIKE 'group_concat_max_len';
-- SET group_concat_max_len = 1048576;
SELECT c.id AS id
, c.name AS name
, GROUP_CONCAT(DISTINCT p.organisationid ORDER BY p.organisationid) AS promoter_list
FROM competition c
LEFT
JOIN competition_organisation p
ON p.competitionid = c.id
GROUP
BY c.id
, c.name
ORDER
BY c.id
, c.name
请注意,如果GROUP\u CONCAT
生成的字符串长度超过GROUP\u CONCAT\u max\u len
,该字符串将自动截断为允许的长度。(无错误,无警告)
将返回字符串的字节长度与系统变量的值进行比较,以检测字符串是否已被截断
如果需要或有充分的理由这样做,查询中也可以包含组织
表
SELECT c.id AS id
, c.name AS name
, GROUP_CONCAT(DISTINCT o.id ORDER BY o.id) AS promoter_list
FROM competition c
LEFT
JOIN competition_organisation p
ON p.competitionid = c.id
LEFT
JOIN organisation o
ON o.id = p.organisationid
GROUP
BY c.id
, c.name
ORDER
BY c.id
, c.name
(警告:这个答案包含两种改进托尔斯滕答案的方法,但我还没有验证它是否是OP问题的有效解决方案。)
计划A:
左连接(选择…
可能会执行得很差
SELECT id,
name,
( SELECT GROUP_CONCAT(organisationid SEPARATOR ', ')
FROM competition_organization
WHERE competitionid = c.id
) AS promoter_list
FROM competition AS c;
左侧的将转换为相关子查询,当没有任何内容时,该子查询将返回NULL
(或'
?)
方案B:
如果不需要LEFT
,也就是说,如果总是有一个组织列表,那么这种重写可能会更好:
SELECT c.id, c.name, co.promoter_list
FROM ( SELECT competitionid,
GROUP_CONCAT(organisationid SEPARATOR ', ') AS promoter_list
FROM competition_organization
GROUP BY competitionid
) AS co
JOIN competition AS c ON c.id = co.competitionid;
这样做的好处是完全构建所有的组内容
,然后查找id
和name
它假定c
:主键(id)
这两种变体都假定co
:索引(competitionid,organizationid)
有关构建最佳多对多表的详细信息,请参阅。我很确定他们希望您展示进行表联接的技能(并可能在单个查询中全部运行)。我怀疑他们会把分数建立在原始执行计划的基础上。标题上写着1:many,但代码和答案涉及到many:many,到底是哪一个??1:很多人不需要第三个t