【问题标题】:complex sql which runs extremely slow when the query has order by clause当查询有 order by 子句时运行极其缓慢的复杂 sql
【发布时间】:2010-04-22 06:26:10
【问题描述】:

我有以下需要使用的复杂查询。当我运行它时,它需要 30 到 40 秒。但是如果我删除 order by 子句,返回结果需要 0.0317 秒,这与 30 秒或 40 秒相比非常快。

select DISTINCT media.*
        , username 
from album as album
     , album_permission as permission
      , user as user, media as media
where ((media.album_id = album.album_id 
        and album.private = 'yes' 
        and album.album_id = permission.album_id 
        and (permission.email = '' or permission.user_id = '') ) 
or (media.album_id = album.album_id 
      and album.private = 'no' ) 
or media.album_id = '0' ) 
and media.user_id = user.user_id
and media.media_type = 'video'
order by media.id DESC 
LIMIT 0,20  

order by 上的 id 是主键,它也被索引。所以我不知道是什么问题。

我也有专辑和专辑权限表,只是为了检查媒体是公共的还是私人的,如果是私人的,那么检查用户是否有权限。我在想这可能是导致问题的原因。如果我在子查询中这样做会更好吗?如果这是解决方案,也有人可以帮我写那个子查询吗?如果你忍不住写,至少告诉我。这个问题我真的要疯了..

可能的解决方案

是的,我认为子查询是最好的解决方案,因为以下查询运行时间为 0.0022 秒。但我不确定专辑验证是否准确,请检查。

select media.*, username 
from media as media
      , user as user
where  media.user_id = user.user_id 
and media.media_type = 'video'
and media.id in 
    (select media2.id
    from     media as media2
            , album as album
            , album_permission as permission
     where ((media2.album_id = album.album_id  
             and album.private = 'yes'
             and album.album_id = permission.album_id 
            and (permission.email = '' 
                 or permission.user_id = ''))
             or (media.album_id = album.album_id 
                   and album.private = 'no' ) 
              or media.album_id = '0' ) 
     and media.album_id = media2.album_id )            
order by media.id DESC
LIMIT 0,20   

【问题讨论】:

  • 一个很好的问题。如果有人能想到这个我很感兴趣......
  • “请检查” - 您需要自己检查。测试两个查询。它们返回相同的结果吗?
  • 我无法检查查询的验证,它们都返回相同的结果,但我还需要检查私人相册,哪些数据尚不可用.. 但无论如何我稍后会添加它们检查一下..但是这样做是什么以及为什么这样做?我的意思是子查询真的比第一个查询快。我确实对它们都进行了测试,结果是一样的。
  • 请停止使用隐式连接,它们是一种非常糟糕的编程习惯。
  • @HLGEM 您对此查询有何建议?如果不是隐式连接?

标签: mysql sql select


【解决方案1】:

使用 EXPLAIN 来确定为什么没有 ORDER BY 子句会更快:

http://dev.mysql.com/doc/refman/5.1/en/using-explain.html

我也建议使用 ANSI 连接语法重写查询。这可能有助于性能。像这样的:

select DISTINCT media.*
        , username 
from album as album
  inner join media as media on media.album_id = album.album_id
  inner join user as user on media.user_id = user.user_id
  left outer join album_permission as permission on album.album_id = permission.album_id
where ((album.private = 'yes' 
        and (permission.email = '' or permission.user_id = '') ) 
or album.private = 'no' 
or media.album_id = '0' ) 
and media.media_type = 'video'
order by media.id DESC 
LIMIT 0,20  

您还可以将查询分成 2 或 3 个不同的查询并将它们联合在一起以避免外连接。

【讨论】:

  • 你能告诉我为什么你推荐这个查询而不是子查询。因为您的查询需要 0.0897 秒,而子查询需要 0.0016 或 0.0018 秒才能加载。
  • 我个人希望子查询更快,因为您不再需要 DISTINCT。由于您没有从专辑中返回任何数据,因此使用 IN 子句通常更快。但是,如果您至少使用子查询版本,请更改为显式连接,它们更适合维护,并且 FAR 不太可能意外给出不正确的结果)使用隐式连接没有任何好处,因此没有任何理由使用以前的语法20 年前被替换。
  • @HLGEM 你能举出使用显式连接的例子吗.. 这个查询的例子
猜你喜欢
  • 2021-04-22
  • 1970-01-01
  • 2023-03-12
  • 1970-01-01
  • 2010-10-16
  • 2020-05-15
  • 2021-06-23
  • 1970-01-01
  • 2012-03-16
相关资源
最近更新 更多