提高大的mysql选择性能

时间:2018-05-07 08:27:30

标签: mysql sql left-join

我有一个选择从卖家那里得到客户跟随的产品。 这个产品有喜欢,评论,需要计数喜欢,需要计算评论和展示另一件事。 我有where user in来获取用户关注的客户。

问题是,这个选择需要一段时间,我想知道我是否能以某种方式改进它。我的所有ID都是键。

select c.nome, p.foto, c.user, p.user, p.id, p.data, p.titulo, p.youtube, pp.foto, count(DISTINCT likes.user) as likes_count, count(distinct comentarios.id) as comentarios_count, count(DISTINCT l2.user) as count2 

from products p 

join users c on p.user=c.id 
left join profile_picture pp on p.user = pp.user
left join likes on likes.post = p.id
left join comentarios on comentarios.foto = p.id and comentarios.delete = 0  
left join likes l2 on l2.post = p.id and l2.user = ?

where (p.user in (select following from following where user =? and block=0) or p.user=?) and p.delete='0'
group by p.id
order by p.id desc limit ?

解释: enter image description here

3 个答案:

答案 0 :(得分:4)

使用delete和user列在 products 表中应用索引(使用复合索引)。

应用适当的索引用户

SELECT c.nome, p.foto, c.user, p.user, p.id, p.data, p.titulo, p.youtube, pp.foto, COUNT(DISTINCT likes.user) AS likes_count, COUNT(DISTINCT comentarios.id) AS comentarios_count, COUNT(DISTINCT l2.user) AS count2 

FROM products p 

LEFT JOIN users c ON p.user=c.id 
LEFT JOIN profile_picture pp ON p.user = pp.user
LEFT JOIN likes ON likes.post = p.id
LEFT JOIN comentarios ON comentarios.foto = p.id AND comentarios.delete = 0  
LEFT JOIN likes l2 ON l2.post = p.id AND l2.user = ?

WHERE c.id IS NOT NULL AND  (p.user IN (SELECT following FROM following WHERE USER =? AND block=0) OR p.user=?) AND p.delete='0'
GROUP BY p.id
ORDER BY p.id DESC LIMIT ?

使用上述查询可以为您提供更好的性能

答案 1 :(得分:3)

TL; DR

根据您的解释,您认为products上没有索引键(user, delete, id)。这可能是当前查询的最大爆炸。

我要假设,因为你问这个你不知道EXPLAIN,即使你做了,也许很难解析方向继续前进如果你读过它就做

简而言之,假设您没有要处理的主要存储/内存问题,并且可以在表中添加索引,我建议您需要在表上添加以下索引:

  • products
  • 上的表格(user, delete, id)的综合索引
  • likes
  • 上的表格(post, user)的综合索引
  • comentarios上的表(foto, delete)的综合索引。 我讨厌保留词语后的栏目(如删除)!!!!
  • following
  • 上的表格(user, block)的综合索引

这会使连接有效但不是100%覆盖,在这种情况下,您可能不希望从您的选择值。

可能已经存在符合上述要求的现有索引,任何以上述值(按照确切顺序)开头的索引都将足够好。例如,如果您在likes上拥有表(post, user, some_other_column)的索引,则它已经提供了我在(post, user)上建议索引所需的所有内容。关键是需要的值必须完全相同。

现在有很多细微的索引编制和很多你想要学习的东西,但这应该可以解除你的工作。

只是抛出一些额外的东西:

  • 您应该在与其相关的表和列之后命名外键。例如comentarios.foto如果确实是产品表中的id,则会更好地命名为comentarios.products_id。这种清晰的命名将有助于防止错误/错误,提高编写新查询的效率,并最大限度地减少未来开发人员试图理解您的架构的理智。
  • 正如几位评论者所提到的,了解如何在查询中阅读Mysql EXPLAIN。只需在查询之前添加关键字EXPLAIN并运行它。结果显示了查询引擎最初计划执行查询的内容(实际上可能会在执行期间发生偏差,但通常会非常适合)。从中您可以看到可能需要索引来改善执行。

答案 2 :(得分:1)

除了Ray对索引的出色建议之外,我还建议您尝试将IN重写为EXISTS。优化者很少永远不会自己做,但它通常更便宜。所以

p.user in (select following from following where user =? and block=0)

应该阅读

exists (select * from following where user = ? and block = 0 and following = p.user)

following (user, following, block)following (following, user, block)上创建综合索引,以支持上述EXISTS的子查询。这里很难猜出userfollowing中的哪一个具有更好的选择性。他们可能非常相似,所以两个订单都应该这样做。可以肯定的是,检查哪个列在表中具有更多不同的值并将其放在第一个。