MySql Group by 함수의 올바른 열기 방법

2756 단어
그룹 함수를 사용할 때 결과 집합을 선별하여 겪는 문제점과 해결 방법
1. 장면 적용
시계가 두 장 있어요.
문장표(한 쌍의 다중 메모표)tposts: oid, posts_name 메모 테이블 tcomment: oid, posts_id, msg_content, create_time
2. 수요 분석
모든 글의 최신 답장 내용을 조회하다
3. SQL 작성

select 
  tp.oid,
  tp.posts_name,
  tc.msg_content,
  tc.create_time
from t_posts tp 
left join t_comment tc on tp.oid = tc.posts_id
group by tp.oid having create_time = max(create_time)

현재 두 개의 문장이 있다고 가정하면 A, B(답장이 데이터베이스에 기록된 순서는 다음과 일치)
A          : 2019-09-10   
A          : 2019-09-11   
B          : 2019-09-01   
B          : 2019-09-09 

위의 sql를 실행하면 결과 집합이 대량의 기록을 잃어버렸고 결과가 잘못된 것을 발견할 수 있습니다. 조회 자료를 통해 알 수 있습니다.
mysql의 having은 그룹 by 이후에 실행됩니다. 즉, 먼저 그룹을 나누고 필터를 하지만 두 개 이상의 메시지 기록이 존재하기 때문에 그룹을 나눈 후의 결과집은 각 메시지의 첫 번째 메시지만 그룹 이후의 기록 정보로 합니다. 이때 having createtime = max(create time) 그러면 max(create time)가 현재 그룹의 최대 시간입니다.
: 2019-09-10 및 2019-09-09
그래서 상기 ql에서 결과 집합을 잃어버릴 수 있습니다
4. SQL 개조
그룹을 나누어 합친 중복 결과 집합이 rownum에서 가장 작은 것임을 알기 때문에, sql를 다음과 같이 개조할 수 있습니까?

select 
  tp.oid,
  tp.posts_name,
  tc.msg_content,
  tc.create_time
from t_posts tp 
left join t_comment tc on tp.oid = tc.posts_id
group by tp.oid having create_time = max(create_time)
--        sql
order by tc.create_time desc

실행 후에도 여전히 작동하지 않음, order by가 그룹 by & having 이후
나중에 생각해 보니까 하빙 없이 order by로 팀을 나눈 후의 결과를 최적화할 수 있을까요?
having create_time = max(create_time)
select 
  tp.oid,
  tp.posts_name,
  tc.msg_content,
  tc.create_time
from t_posts tp 
left join t_comment tc on tp.oid = tc.posts_id
group by tp.oid 
order by tc.create_time desc

결과 집합 오류, 그룹 결과에 영향을 주지 않습니다. rownum 최소 그룹에 따라 결과 집합을 합쳐서 정렬합니다.
5. 최종 개조 버전
order by는 나중에 그룹 by에만 영향을 미칠 수 있기 때문에 그룹 by 전에 결과 집합을 정렬한 다음에 그룹을 나눌 수 있지 않을까요?

select * from (
  select 
    tp.oid,
    tp.posts_name,
    tc.msg_content,
    tc.create_time
  from t_posts tp 
  left join t_comment tc on tp.oid = tc.posts_id
  order by tc.create_time desc
) t 
group by t.oid 

여전히 쓰기 어려운 것을 발견했지만, 하위 조회가 확실히 먼저 정렬되었다
조회(explain)를 통해 하위 조회의order by가 최적화되지 않은 것을 발견했습니다. 해결 방법:
4
  • 하위 검색에서 limit 99999
  • 4
  • 하위 조회에서where 조건을 사용하고createtime = (select max(create_time) from t_comment group by oid)
  • 
    select * from (
      select 
        tp.oid,
        tp.posts_name,
        tc.msg_content,
        tc.create_time
      from t_posts tp 
      left join t_comment tc on tp.oid = tc.posts_id
      order by tc.create_time desc limit 9999
    ) t 
    group by t.oid 
    

    큰 성과를 거두다
    빌드 테이블 문:
    클릭하여 다운로드
    추가 지식 포인트:
    mysql5.5와 mysql 5.7 버전 차이: 5.7+버전, limit을 사용하지 않으면 그룹 by는order by를 최적화합니다
    개인 블로그 클릭

    좋은 웹페이지 즐겨찾기