结果: 我使用了三种方法:
我已经用"解释"制作了一些统计数据。和"剖析"这解释了每个查询必须完成的工作,以下结果并不令人惊讶:stats
相对结果:
1715%
原始邮寄
想法是连接4个表,每次使用相同的PK,然后计算每个连接分别给出的行数。
显而易见的答案是每次加入......与子查询分开。
但是有可能用一个查询来做吗?它会更有效率吗?
select "LES CIGARES DU PHARAON" as "Titre",
(select count( payalb.idPays)
from album alb
left join pays_album payalb using ( idAlb )
where alb.titreAlb = "LES CIGARES DU PHARAON") as "Pays",
(select count( peralb.idPers)
from album alb
left join pers_album peralb using ( idAlb )
where alb.titreAlb = "LES CIGARES DU PHARAON") as "Personnages",
(select count( juralb.idJur)
from album alb
left join juron_album juralb using ( idAlb )
where alb.titreAlb = "LES CIGARES DU PHARAON") as "Jurons"
;
+------------------------+------+-------------+--------+
| Titre | Pays | Personnages | Jurons |
+------------------------+------+-------------+--------+
| LES CIGARES DU PHARAON | 3 | 13 | 50 |
+------------------------+------+-------------+--------+
表专辑行:22
表pays_album行:45
table personnage_album rows:100
表juron_album行:1704
以下是我的尝试:
select alb.titreAlb as "Titre",
sum(case when alb.idAlb=payalb.idAlb then 1 else 0 end) "Pays",
sum(case when alb.idAlb=peralb.idAlb then 1 else 0 end) "Personnages",
sum(case when alb.idAlb=juralb.idAlb then 1 else 0 end) "Jurons"
from album alb
left join pays_album payalb using ( idAlb )
left join pers_album peralb using ( idAlb )
left join juron_album juralb using ( idAlb )
where alb.titreAlb = "LES CIGARES DU PHARAON"
group by alb.titreAlb
;
+------------------------+------+-------------+--------+
| Titre | Pays | Personnages | Jurons |
+------------------------+------+-------------+--------+
| LES CIGARES DU PHARAON | 1950 | 1950 | 1950 |
+------------------------+------+-------------+--------+
但它计算完整联接表的总行数,...(1950 = 3 * 13 * 50)
架构:https://github.com/LittleNooby/gbd2015-2016/blob/master/tintin_schema.png
表内容:https://github.com/LittleNooby/gbd2015-2016/blob/master/tintin_description
如果你想玩它玩:
db_init:https://github.com/LittleNooby/gbd2015-2016/blob/master/tintin_ok.mysql
答案 0 :(得分:2)
出于优化目的,一个好的经验法则是加入更少,而不是更多。实际上,您应该尝试尽可能少地加入尽可能少的行。使用任何其他连接,您将增加成本而不是增加成本。因为mysql基本上只会生成一个大的乘法矩阵。其中很多都被索引和其他东西所优化。
但是要回答你的问题:假设桌子有唯一的密钥,而idalb是专辑的唯一密钥,那么实际上只有一个大连接可以计算。然后,只有这样,你才能像你的代码那样做:
select alb.titreAlb as "Titre",
count(distinct payalb.idAlb, payalb.PrimaryKeyFields) "Pays",
count(distinct peralb.idAlb, peralb.PrimaryKeyFields) "Personnages",
count(distinct juralb.idAlb, juralb.PrimaryKeyFields) "Jurons"
from album alb
left join pays_album payalb using ( idAlb )
left join pers_album peralb using ( idAlb )
left join juron_album juralb using ( idAlb )
where alb.titreAlb = "LES CIGARES DU PHARAON"
group by alb.titreAlb
其中PrimaryKeyFields代表连接表的主键字段(您必须查找它们)。
Distinct
将删除其他联接对计数的影响。但遗憾的是,一般而言,distinct
不会消除联接对成本的影响。
虽然,如果您的索引覆盖了表的所有(idAlb + PrimaryKeyFields)字段,那么它甚至可能与原始解决方案一样快(因为它可以优化distinct
以不进行排序)并且将接近您的想法(只需遍历每个表/索引一次)。但是在正常或最坏情况下,它应该比合理的解决方案(比如SlimGhost&#39)更差 - 因为它会找到最佳策略是值得怀疑的。但是玩它并检查解释(并发布结果),也许mysql会做一些疯狂的事情。
答案 1 :(得分:1)
就“db的最少工作”而言,我认为以下内容对于您的架构来说都是正确的I / O逻辑I / O.但是要明白,除非你查看解释计划(预期和实际),否则你无法确定。
仍然,我建议尝试这一点 - 它只访问“alb”表一次,而原始查询需要访问它四次(一次获取“基本”专辑记录,然后三次查询三个子查询)。
select alb.titreAlb as "Titre",
(select count(*) from pays_album t2 where t2.idAlb = alb.idAlb) "Pays",
(select count(*) from pers_album t2 where t2.idAlb = alb.idAlb) "Personnages",
(select count(*) from juron_album t2 where t2.idAlb = alb.idAlb) "Jurons"
from album alb
where alb.titreAlb = "LES CIGARES DU PHARAON"