Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/mysql/71.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
MySQL:如何选择和处理;n到n“;与性能相关的数据_Mysql_Sql_Performance_Select_Relationship - Fatal编程技术网

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