【问题标题】:select taking a lot of time on table with many rows选择在有很多行的表上花费大量时间
【发布时间】:2018-05-13 21:31:36
【问题描述】:

我有这个选择:

select 'like' prefix
     , l.post
     , l.data as data
     , l.user
     , concat(k.user, ' liked you') as logs 
  from likes l 

inner join posts p on l.post = p.id 
inner join cadastro k on l.user = k.id 
where p.user = 1 and l.user <> p.user

order by data desc
limit 10

耗时 2.3993 秒。

有什么改进的想法吗?

`likes` (
  `id` int(11) UNSIGNED NOT NULL AUTO_INCREMENT,
  `user` int(11) UNSIGNED NOT NULL,
  `post` int(11) UNSIGNED NOT NULL,
  `data` datetime NOT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `user_post` (`user`,`post`),
  KEY `post_user` (post, user),
  FOREIGN KEY (`user`) REFERENCES cadastro (`id`),
  FOREIGN KEY (`post`) REFERENCES posts (`id`) ON DELETE CASCADE
)

`posts` (
  `id` int(11) UNSIGNED NOT NULL AUTO_INCREMENT,

`cadastro` (
  `id` int(11) UNSIGNED NOT NULL AUTO_INCREMENT,

有什么想法可以加快速度吗?我也尝试在喜欢数据上添加索引,但没有发现差异。

【问题讨论】:

  • 我觉得我们已经这样做了?!?
  • @Strawberry 是的!但是查询是在一个联合上的,我注意到这个类似的部分是有问题的部分,所以我决定在这篇文章中更好地解释。我也试过你的提示,改变&lt;&gt; 部分,但结果是一样的。
  • 但是我们已经到了where p.user = 1 and l.user &lt;&gt; 1。那是怎么回事?
  • @Strawberry 我没有注意到任何速度改进;/

标签: mysql indexing query-optimization


【解决方案1】:

这是您的查询:

select 'like' as prefix, l.post, l.data as data, l.user,
        concat(k.user, ' liked you') as logs
from likes l join
     posts p
     on l.post = p.id oin
     cadastro k
     on l.user = k.id 
where p.user = 1 and l.user <> p.user
order by data desc
limit 10;

对于此查询,您需要post(user, id)likes(post, user, data)cadastro(id, user) 上的索引。

您不能做太多的事情来消除order by 的开销,但这应该会加快查询的连接和过滤部分。

【讨论】:

  • 谢谢,它降到了 1.5186 秒。不是那么好,但有点快。
【解决方案2】:
select  'like' prefix ,
        l.post ,
        l.data as data ,
        l.user ,
        ( SELECT concat(user, ' liked you')
              FROM cadastro  WHERE id = l.user ) AS logs
    from  likes l
    inner join  posts p  ON l.post = p.id
    where  p.user = 1
      and  l.user <> p.user
    order by  data desc
    limit  10

索引:

p: (user, data, id)  -- 'covering'; helps WHERE; may help ORDER BY
l: (post)
cadastro: I assume you have PRIMARY KEY(id)

进一步改进:将likes 索引从

PRIMARY KEY (`id`),
UNIQUE KEY `user_post` (`user`,`post`),
KEY `post_user` (post, user),

PRIMARY KEY(post, user),
INDEX(user, post)

并摆脱id

警告:如果没有人“喜欢你”,则此查询的结果集可能会有所不同。如果这是一个问题,我将重新制定它以使用“派生”表。

通过将 cadastro 查找移动到子查询中,我认为该操作的发生频率低于 cadastro 在JOIN 中的情况。这不是一种通用优化——注意WHERE 子句很复杂,因为它涉及多个表。我不清楚p 上的索引是否会一直到data,并且对LIMIT 有帮助。如需进一步调查,请提供EXPLAIN FORMAT=JSON SELECT ...

【讨论】:

  • 非常感谢!!这很奇怪,但在 cadastro 中使用子查询有助于将速度提高到 4 倍。你能解释一下为什么它比内部连接更好吗?
  • @RickJoe - 我试图通过我的答案中添加的段落来回答你。
猜你喜欢
  • 1970-01-01
  • 2017-04-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-05-10
  • 2015-08-02
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多