我想找到一种改进查询的方法,但是看来我已经完成了所有工作。让我给你一些细节。
以下是我的查询:
SELECT
`u`.`id` AS `id`,
`p`.`lastname` AS `lastname`,
`p`.`firstname` AS `firstname`,
COALESCE(`r`.`value`, 0) AS `rvalue`,
SUM(`rat`.`category` = 'A') AS `count_a`,
SUM(`rat`.`category` = 'B') AS `count_b`,
SUM(`rat`.`category` = 'C') AS `count_c`
FROM
`user` `u`
JOIN `user_customer` `uc` ON (`u`.`id` = `uc`.`user_id`)
JOIN `profile` `p` ON (`p`.`id` = `u`.`profile_id`)
JOIN `ad` FORCE INDEX (fk_ad_customer_idx) ON (`uc`.`customer_id` = `ad`.`customer_id`)
JOIN `ac` ON (`ac`.`id` = `ad`.`ac_id`)
JOIN `a` ON (`a`.`id` = `ac`.`a_id`)
JOIN `rat` ON (`rat`.`code` = `a`.`rat_code`)
LEFT JOIN `r` ON (`r`.`id` = `u`.`r_id`)
GROUP BY `u`.`id`
;
注意:某些表和列的名称是自动隐藏的。
现在让我给您一些体积数据:
user => 6534 rows
user_customer => 12 923 rows
profile => 6511 rows
ad => 320 868 rows
ac => 4505 rows
a => 536 rows
rat => 6 rows
r => 3400 rows
最后,我的执行计划:
我的查询当前确实在大约1.3到1.7秒内运行,这当然足以使我的应用程序的用户烦恼……而且fyi结果集由165行组成。
有什么办法可以改善这一点?
谢谢。
编辑1(以下是对Rick James的回答): 不使用FORCE INDEX时速度和说明如何?
令人惊讶的是,当我不使用FORCE INDEX时它会变得更快。老实说,我真的不记得为什么要进行这种更改。在进行各种尝试之一后,我可能发现它在性能方面有更好的结果,此后一直没有删除它。
当我不使用强制索引时,它使用另一个索引ad_customer_ac_id_blocked_idx(customer_id,ac_id,已阻止),时间约为1.1秒。 我不太了解它,因为当我们谈论customer_id的索引时,fk_ad_customer_idx(customer_id)是相同的。
答案 0 :(得分:6)
摆脱FORCE INDEX
。即使昨天有所帮助;明天可能会受伤。
其中一些指数可能是有益的。 (很难预测;只需将它们全部添加即可。)
a: (rat_code, id)
rat: (code, category)
ac: (a_id, id)
ad: (ac_id, customer_id)
ad: (customer_id, ac_id)
uc: (customer_id, user_id)
uc: (user_id, customer_id)
u: (profile_id, r_id, id)
(这假设id
是每个表的PRIMARY KEY
。请注意,没有人先拥有id
。)以上大部分内容都是“覆盖”。
有时可能有用的另一种方法:在加入任何不必要的表之前先收集SUMs
。但是似乎p
是唯一不涉及从u
(GROUP BY
的目标)到r
和rat
(用于聚合)的表。看起来像这样:
SELECT ..., firstname, lastname
FROM ( everything as above except for `p` ) AS most
JOIN `profile` `p` ON (`p`.`id` = most.`profile_id`)
GROUP BY most.id
这避免了在进行大多数联接和GROUP BY
时浪费名字和姓氏。
在进行JOINs
和GROUP BY
时,请务必仔细检查汇总。您的COUNTs
和SUMs
可能会比应有的大。
答案 1 :(得分:1)
首先,您不需要在查询中tick
。everyTableAndColumn
,也不需要结果列,别名等。tick
标记主要用于您与一项保留的工作,以便解析器知道您要引用的是特定的列...例如具有一个名为“ JOIN”的COLUMN的表,但JOIN是SQL命令的一部分...请参阅将引起的混乱。也有助于提高可读性。
下一步,这只是个人喜好,可以帮助您和其他关注您的数据及其关系。我将联接显示为从何处缩进。正如您在下面看到的,我看到了如何从用户(u别名)到达大鼠别名表的链...您只能通过深入5个级别到达那里,然后将第一个表放在左侧-联接的一侧(来自表)然后=表联接到联接右侧。
现在,我可以看到它们之间的关系,我建议以下内容。在具有条件以及适当的id / value的表上建立COVERING索引。这样一来,查询就可以最好地获取索引页中的数据,而不必访问原始数据。因此,这里是索引的建议。
table index
user_customer ( user_id, customer_id ) -- dont know what your fk_ad_customer_idx parts are)
ad ( customer_id, ac_id )
ac ( id, a_id )
a (id, rat_code )
rat ( code, category )
经过重新格式化的查询,以提高可读性并查看表之间的关系
SELECT
u.id,
p.lastname,
p.firstname,
COALESCE(r.value, 0) AS rvalue,
SUM(rat.category = 'A') AS count_a,
SUM(rat.category = 'B') AS count_b,
SUM(rat.category = 'C') AS count_c
FROM
user u
JOIN user_customer uc
ON u.id = uc.user_id
JOIN ad FORCE INDEX (fk_ad_customer_idx)
ON uc.customer_id = ad.customer_id
JOIN ac
ON ad.ac_id = ac.id
JOIN a
ON ac.a_id = a.id
JOIN rat
ON a.rat_code = rat.code
JOIN profile p
ON u.profile_id = p.id
LEFT JOIN r
ON u.r_id = r.id
GROUP BY
u.id