1. FROM, JOIN

 

- 먼저 FROM ( 테이블 ) JOIN ( 테이블 ) 이 실행되어 데이터셋을 뽑아냅니다.

 

- Sub Query문 (서브쿼리)도 실행되며 임시 테이블이 생성될 수 있습니다.

 

 

 

2. WHERE

 

- 1에서 뽑아낸 데이터셋에서 WHERE 조건문에 기재된 제약조건 대로 이를 충족하는 행만 뽑아냅니다.

 

 

 

3. GROUP BY

 

- 2에서 뽑아낸 데이터셋에 대해서 그룹조건을 적용하여 그룹으로 묶어줍니다.

 

 

 

4. HAVING

 

- 그룹으로 묶여진 데이터셋에 대해서 HAVING 조건절을 만족하는 행만이 남습니다.

 

 

 

5. SELECT

 

- 4까지 완료된 데이터 셋에 대하여 SELECT문을 실행하여 원하는 칼럼을 설정합니다.

 

 

 

6. DINSTINCT

 

- DISTINCT를 사용할 경우 이 단계에서 중복되는 행은 제거 됩니다.

 

 

 

 

7. ORDER BY

 

- 지금까지 만들어진 데이터셋을 어떤식으로 정렬 할 것인지 정합니다(오름차순, 내림차순)

 

 

 

8. LIMIT / OFFSET

 

- 최종적으로 범위를 지정 (지정된 범위를 벗어나는 행을 제거) 합니다.

 

 

 

 

 

[출처]:

https://sqlbolt.com/lesson/select_queries_order_of_execution
jaimemin.tistory.com/1475?category=1060172

 

데이터베이스 쿼리 실행 순서

회사를 직접적으로 언급할 수는 없지만 데이터베이스 쿼리 실행 순서를 질문받은 적 있습니다. 코딩 테스트 난이도 정도의 쿼리 작성에는 어느 정도 자신이 있었지만 실행 순서는 한 번도 생각

jaimemin.tistory.com

 

SQLBolt - Learn SQL - SQL Lesson 12: Order of execution of a Query

Now that we have an idea of all the parts of a query, we can now talk about how they all fit together in the context of a complete query. Complete SELECT query SELECT DISTINCT column, AGG_FUNC(column_or_expression), … FROM mytable JOIN another_table ON m

sqlbolt.com

 

'Web & App > Mysql' 카테고리의 다른 글

Pagenation(페이징) [Offset-based, Cursor-based)  (0) 2020.10.17
mysql 외부 접속 허용  (0) 2020.08.17

1. 페이지네이션(페이징) 이란 ?

- 서버와 클라이언트의 상황에서 보통 모든 데이터를 한 번에 가져오지 않습니다.

 

- 보통 필요한 갯수를 지정하고 상황에 맞춰 정렬기준이 조건에 추가됩니다( 정렬기준 + 갯수)

 

- 이러한 조건을 맞춰서 데이터를 가져오는 것을 Pagenation(페이지네이션), 페이징 이라고 합니다.

 

- 페이지네이션을 처리하는 방법으로는 대표적으로 1. 오프셋 기반 페이지네이션, 2.커서 기반 페이지네이션

  으로 처리 가능합니다.

 

- 비교적 구현이 매우 간단한 오프셋 기반 페이지네이션 부터 살펴보겠습니다.

 

 

 

2. Offset-based Pagination (오프셋 기반)

 

- 제가 사용하는 MySQL로 말씀드리자면 LIMIT을 사용하여 개수를 지정하면 됩니다.

SELECT UserId FROM membership ORDER BY CreateAt desc LIMIT 20,40

 

- 좀 더 일반적인 변수를 사용한 쿼리문은 이렇게 되겠네요

( pagenum -> 페이지(1.2.....) )

( takenum -> 한번에 불러올 데이터(row) 수)

'SELECT UserId FROM membership
ORDER BY CreateAt DESC
LIMIT' + ( $takenum*($pagenum-1))+','+$takenum;

- 이렇듯 매우 직관적이고 이해하기가 쉽습니다. 사용하기도 편하구요.

 

- 보통 밑에 이동할 수 있는 페이지가 있고 페이지를 뛰어 넘어갈 수 있다면 offset 기반입니다.

 

- 하지만 제가 생각하는 가장 와닿는 문제는 예를 들겠습니다.

 

- 사용자가 매우 많은 사이트에서 글을 쓰는 사람이 매우 많다고 하겠습니다.

 

- 초당 평균 20개의 새로운 데이터가 들어온다고 가정하고, 한 페이지당 20개의 데이터를

 

- 보여준다면, 이를 오프셋 기반으로 구현을 한다면 1페이지의 20개의 글을 본 사람이

 

- 2페이지의 글을 보려고 눌렀을때, 방금 본 20개의 데이터를 그대로 다시 보게 됩니다.

 

- 즉, 중복데이터를 출력하게 됩니다. 그리고 이런 최악은 아니더라도 생각보다 이런 상황은

 

- 빈번하게 나타나고, 아마  경험하신 분들도 많이 있으실거라 생각합니다.

 

- 또 다른 문제는, 정렬기준 조건에 따라서 row가 몇번 째 데이터인지 바뀌게 되는데,

 

- 당연히 DB는 모든 경우에 따른 rownum을 가지고 있지 않기때문에 

 

- row의 수가 많아질수록 성능에 문제가 생기게 됩니다.

 

-이러한 단점을 보완해줄 수 있는 것이 커서 기반 페이지네이션 입니다.

 

 

 

3. Cursor-based Pagination (커서 기반)

 

- 음.... cursor를 포인터라고 생각하면 이해가 빠를 것 같습니다.

 

- cursor를 만들어 놓고 "이 cursor가 가리키는 것 다음 부터 n개의 데이터를 주세요" 하는 방식입니다.

 

- 오프셋 방식을 굳이 예로 들자면 "n개의 데이터를 page-1만큼 스킵하고 그 다음부터 n개의 데이터를 주세요"

  가 될 것 같네요.

 

- 만약 cursor가 int로 된 UserId라면 UserId 자체를 커서로 사용하여도 상관이 없습니다. (UserId - PK)

 

- 하지만 cursor를 회원가입 시기(CreateAt) 라고 지정한다면 어떻게 될까요?????

(데이터가 만들어진 순서대로 출력하고 싶을 때)

 

- 상황 설명을 위해 LIMIT를 사용해서 현재 가정한 테이블의 상태를 확인해보겠습니다.

  (CreateAt은 설명의 편의성을 위해서 간단한 숫자로 대체하여 표현하겠습니다.)

 

SELECT UserId,CreateAt FROM membership 
ORDER BY CreateAt ASC LIMIT 4

 

UserId CreateAt
123 1
124 2
120 3
114 4

 

- 전혀 문제가 없어 보입니다. 하지만 만약에 UserId가 "114"와 동시에 가입한 115,116,117이 있을경우

 

- cursor를 CreateAt으로 설정할 경우 cursor>4 인 리스트를 다음페이지에 불러올 텐데 그럴경우

 

- 115,116,117의 데이터는 누락이 발생합니다.

 

- 여기서 알 수 있는 것은

 

- "커서 기반 페이지네이션을 위해서는 정렬 기준에 포함되는 필드 중 하나이상은 반드시 고유값을 가져야 한다는 것 "

 

- 설명을 위해 테이블의 상황을 살짝 수정하겠습니다. 아래와 같습니다.
  (말이 좀 안되지만 age는 중복값이 없는 고유값이라고 가정을 좀 하겠습니다.)

UserId CreateAt Age
123 1 17
124 2 18
120 3 19
114 4 20

- 이 다음 페이지의 데이터를 얻기 위해서는 다음과 같은 쿼리를 날리면 됩니다.

 

SELECT UserId,CreateAt,Age FROM membership
WHERE (CreateAt >4) or (CreateAt=4 and Age>20)
ORDER BY CreateAt ASC, Age ASC LIMIT 4

- 이렇게 날리면 CreateAt이 4 인 115,116,117도 누락되지 않습니다.

 

- 문제가 모두 해결된 것 처럼 보이지만 여기서도 제가 생각하는 문제점 중 하나는

 

- 이렇게 조건절에 필요사항이 달림에 따라서 클라이언트 측에서도 이를 이해하고

 

- ORDER BY에 달려있는 필드 들을 이해하고 이에 해당하는 값들을 요청시 마다 보내야 하는데

 

- 당연히 클라이언트 측은 그걸 좋아하지 않고 원치 않습니다

 

- 그러므로 WHERE절에 걸리는 조건들을 이용해서 고유한 값인 CURSOR(커서)를 만들면 됩니다.

 

- 간단한 예시로 CreateAt이 최대 6자라고 하고 AGE가 최대 3자 라고 가정하면,

  

- 두 가지를 합쳐서 "4" + "17" => "000004017" 이런 식으로 가공하여 CURSOR 값으로 사용을 하는 것입니다.

 

- 커서를 기준으로 출력 후 , 그 다음 리스트는 이 커서 기준으로 다음부터 데이터를 가져오면

 

- 위의 문제들이 해결된다는 것을 알 수 있습니다.

 

 

 

 

 

4. Offset vs Cursor

 

- 제 생각에는 왠만하면 커서를 이용하는 것이 좋은 것 같습니다만

 

- 데이터의 입력이 매우 드물고, 또는 중복되는 데이터가 나와도 크게 상관이 없는경우

 

- 데이터의 수 자체가 그리 많지 않아서 성능에 딱히 연연하지 않아도 되는 경우

 

- 등에서는 오프셋을 사용해도 크게 문제되지는 않을 것 같습니다.

 

- 하지만 유저가 접속해서 사용하는 경우 커서 기반을 사용하는 것이 좋습니다.

'Web & App > Mysql' 카테고리의 다른 글

Query문의 실행 순서  (2) 2020.10.27
mysql 외부 접속 허용  (0) 2020.08.17

ec2 인스턴스에서 임대한 서버에 apm이나 nginx mysql php 등등 을 구축해서

 

사용을 하려다 보면 예상치 못한 오류들을 만나는데요 

 

권한과 관련된 문제들도 많이 만나고, ec2의 경우 유저명과 관련된 오류도 만나고...(ubuntu, ec2-user...)

 

..... 방화벽과 관련된 문제들도 만나는데요

 

저는 데이터그립과 ec2 서버에 설치된 mysql 데이터 베이스를 연동해서 사용하려 하는데 test connection에서

 

오류가 나타나서 확인해보니

 

ec2에 설치된 mysql 이 외부에서 접속이 가능하도록 해주어야 연결이 되더군요  !

 

아래와 같이 입력 하셔서 외부접속을 허용해주시면 됩니다. !

 

GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' IDENTIFIED BY 'root의 패스워드';

'Web & App > Mysql' 카테고리의 다른 글

Query문의 실행 순서  (2) 2020.10.27
Pagenation(페이징) [Offset-based, Cursor-based)  (0) 2020.10.17

+ Recent posts