row_number() 윈도우 함수와 h2 DB, Mysql DB에 대해서 질문드립니다. 0 2 3,815

by 용갈용갈 [SQL Query] mysql h2 query [2025.03.18 00:51:51]



1
2
3
4
5
6
7
8
9
SELECT
    t.member_id AS memberId,
    m.nickname AS nickname,
    (t.wpm * 3 + t.acc * 2 + t.cpm) AS score,
    ROW_NUMBER() OVER (ORDER BY (t.wpm * 3 + t.acc * 2 + t.cpm) DESC) AS 'rank'
FROM typing t
JOIN member m ON t.member_id = m.id
ORDER BY score DESC
LIMIT 50;

 

이 쿼리에 대해서 질문드립니다. 많은 고민을 해보았고, 많은 테스트를 거쳐보았지만, 명확한 이유를 알지 못하여 질문글 남기게 되었습니다.
해당 쿼리를 h2 데이터베이스에 실행해보았을때, 첫번째 첨부 사진과 같이 같은 score에 대해서 순위가 뒤바뀌는 현상을 발견할 수 있었습니다.
이는 row_number() 비결정적 함수이기 때문에 동일한 score에 대해서 늘 같은 결과를 준다는 보장이 없기 때문이고, 또한, order by 절 역시, 같은 조건일 때, 항상 동일한 결과를 준다는 보장이 없기 때문에 해당 현상이 발생하는 것으로 이해했습니다.
[첨부 1 - h2 db / 첨부 2 - mysql db]

그런데, 같은 쿼리를 DBeaver Mysql에서 실행하게 되면, 2번째 첨부파일과 같은 결과가 나타납니다. 즉, rank를 기준으로 정상적으로 오름차순으로 정렬되어 있다는 것을 확인할 수 있습니다.
query cache를 지우고 다시 실행해보았지만, row 순서만 바뀔 뿐 역시나 rank를 기준으로 정렬되어 있는 것을 확인할 수 있었습니다.

Mysql에서의 row_number()를 기준으로 정렬한다는 내부적인 로직이 있나 궁금해서 자료를 많이 찾아보았지만, 그런 내용은 찾아볼 수 없었습니다.
그저 새롭게 알게 된 사실은 row_number() 와 order by 절은 비결정적이므로 pk와 같은 고유한 값을 가지는 컬럼을 2번째 정렬 순서로 하여 결정적으로 바꿔줘야한다는 것입니다.
혹시 이와 관련된 Mysql만의 내부적인 정렬로직이 존재하는지 궁금합니다.

더불어 위 쿼리에서 order by 절을 제거했을 때에도 h2 데이터베이스와 mysql이 다른 양상을 보이는 것을 확인할 수 있었습니다.
h2 데이터베이스에서는 memberId를 기준으로 정렬된 결과를 반환하는 것을 확인했고, mysql에서는 row_number를 기준으로 정렬된 결과를 반환하는 것을 확인할 수 있었습니다.
[첨부 3 - h2 / 첨부 4 - mysql]

이런 현상이 DB마다 내부 구현 로직이 다르다는 것을 알지만, mysql에서 이러한 현상이 발생하는 원인에 대해서 자세하게 알고 싶습니다.  

by 마농 [2025.03.18 13:32:22]

글쎄요?
현상에 대한 이유와 그에 대한 해결법까지 알고 있다면 그만 아닌가 싶습니다.
내부적인 정렬 알고리즘과 동작방식을 이해하면 좋긴 하겠지만.
외부로 공개되지 않은 내용이라 알기도 힘들고
만약 알아 냈다고 해서 그게 지금은 그렇지만 나중엔 달라질 수도 있는 부분입니다.
버전이나 환경에 따라 달라질 수 있는 부분일 것이고,
한가지 방식만 사용한다는 보장도 없을 것입니다.

질문의 쿼리처럼 조인이 동반된 경우라면?
정렬 뿐만 아니라 조인 동작 메커니즘까지도 결과에 영향을 미칠 수 있으니
꼼꼼히 살펴 봐야 할 것입니다.
굳이 이렇게까지...

학구적인 의욕을 꺽고자 쓴 글은 아닙니다.
그냥 제 개인적인 의견일 뿐입니다.


by 용갈용갈 [2025.03.19 00:26:39]

좋은 답변 감사합니다! 아는 지식이 부족하다보니 어디까지 고민해봐야 좋은 고민일까 라는 생각에 매몰되어 해당 질문에 빠져서 나오지 못하고 있는 것 같습니다. 답변주신 내용을 보고 머리를 띵 하고 맞은 것 같습니다! 이런 현상이 있고, 해결 방안은 이렇다라는 것을 알았으니 다음 스텝으로 넘어가도록 하겠습니다! 

감사합니다 :)

댓글등록
SQL문을 포맷에 맞게(깔끔하게) 등록하려면 code() 버튼을 클릭하여 작성 하시면 됩니다.
로그인 사용자만 댓글을 작성 할 수 있습니다. 로그인, 회원가입