15 Jul 2024
조기 졸업
한양대학교에서의 학부 생활은 24년도 1학기를 마지막으로 끝나게 되었다. 대부분의 학교가 4학년부터 강의가 널널해지거나 들어야하는 학점이 적은 경우가 많다. 우리 학교도 크게 다른 점이 없어서, 이렇게 흥미가 생기지 않는 강의를 들으며 4학년을 보내는 것보다 한 학기 일찍 학교를 끝내서 등록금이라도 좀 아끼려고 조기졸업을 신청했다.
어떻게 하는가?
우리 학교에서 조기졸업을 하려면 21학번은 7학기를 진입하는 시점에 학점 4.0 이상, 115학점 이상 수료가 되어 있어야 한다. 또한, 다른 졸업 요건들이 충족되어야 졸업이 가능하기 때문에 실제로 졸업을 하기 위해서는 필수 이수 강의들을 모두 들어두어야 하고, 특히 가장 중요한 졸업프로젝트가 7학기째에 끝나야 한다. 그리고 조기졸업 희망자는 학교에서 크게 신경쓰지 않기 때문에 졸업을 하려면 본인이 챙겨야할 것들을 잘 챙겨야.. 무사히 졸업할 수 있을 것이다. (일례로, 조기졸업 신청 후 결재가 되기까지 시간이 걸렸는데 학과에 전화한 이후 바로 결재가 진행되었다. 물론 우연일 가능성도 있지만 학교에서 따로 나를 위해 뭔가 챙겨주는 것이 아니라는 것)
학점 얘기부터 하자면, 4.0을 넘기는게 관건인데 내 마지막 기억으로는 4.0/4.5가 학과에서 30~40/150 정도의 위치이다. 등수를 보면 알겠지만, 엄청 어렵지는 않지만 그렇게 쉽지도 않은 학점이라 조기졸업이나 대학원을 신경쓰고 있다면 항상 염두에 두고 있어야 한다. 학점을 챙기는 것은 전략적으로 수행할 수 있는 부분이다. 커뮤니티에 “꿀강의”라고 불리는 강의들을 유심히 보고 있다가 수강한다면 도움이 될 것이다. 특히, P/F 강의와 절대평가로 이루어지는 강의들을 수강하면 부담을 많이 덜 수 있다. 4.0을 넘기는 것이 끝이 아니라 6학기만에 115학점을 들어야하는데, 그럴려면 단순 나누기만 해보아도 한 학기에 19학점 이상씩 수강해야 한다는 사실을 깨달을 수 있다. 헉! 그렇다면, 매 학기 힘들게 다녀야 하는가? 대부분의 경우 그렇다. 조기졸업을 상대적으로 늦게 결정해서 나는 3-1과 3-2에 20학점씩 들어야 했었다. 그러고도 계절에 3학점을 더 들어서 겨우 115학점을 넘겼다. 조기졸업을 계획하고 있다면 나는 계절학기를 적절하게 활용할 것을 권한다. 계절마다 3학점씩만 들어두어도 한 학기가 편해질 수 있다. 물론 방학에 학교를 나가는 것은 단점이지만, 사이버 강의 같은것도 있으니 잘 활용하기를 바란다.
이렇게 힘들게 학점을 채우고 나면 끝이 아니다! 우리 학교 컴퓨터소프트웨어학부는 졸업을 하기 위해서 졸업프로젝트를 할 것을 요구한다. 조기졸업을 하기 위해서는 4-1에 졸프가 끝나야 한다. 졸프는 1년짜리이고 이걸 마음대로 줄일 수 없다. 그렇기 때문에, 조기졸업자들은 필수로 3-2부터 졸프를 시작해야 한다. 졸프는 보통 2~3인 1팀으로 진행되기 때문에, 신청 시점에 팀이 짜여져 있어야 한다. 이 모든 사실을 몰랐던 나는 에타에서 졸프 인원을 구하는 글을 보고 연락을 해서 졸프를 진행했고, 결론만 말하자면 좋은 분을 만나서 졸프가 어찌저찌 잘 진행됐었다. 그렇지만, 급하게 졸프 팀을 구한 점에서 내가 하고 싶은 주제를 고르기도 어려웠고(솔직히 마음에 드는 주제는 없긴 했다) 불안함도 있었다. 그래서 만약 졸프를 일찍 시작하게 된다면, 마음이 맞는 사람들한테 같이 졸프하자고 한 번 꼬셔보는 걸 추천한다.
졸프는 트렌드를 따라 대게 머신러닝 관련된 주제들이 많다. 나는 굳이굳이 시스템 관련 주제를 픽했지만, 다시 돌아가게 된다면 그냥 무난한 ML 주제를 하나 골라 수행했을 것 같다 (이전에는 모든 토픽들이 ML에 절여진 것에 대해 불만이 많았는데, 연구 사례나 활용을 보면서 그런 반감이 줄어들었음). 졸프는 꼭 자신이 원하는 분야와 관련되어야 할 필요는 없다. 관련 있는 주제를 택한다고 해도 의미있는 결과를 뽑기가 생각보다 어려워서 남는게 크게 많지 않을 수 있다. 그렇기 때문에 현실적으로 나는 그냥 이후에 활용할 수 있을만한 ML 관련 주제들을 한 번 건드려보는 것이 나쁘지 않다고 생각한다. 물론, 학부생들한테 연구 서버들을 빌려주고 그런건 좀 어려운 것으로 보여서 이런 주제를 픽하면 학습을 돌리고 하는 부분에서 개인 사비가 지출될 수는 있을 것이다.
이렇게 졸프를 잘 정해서 수행하고 꾸준히 보고서와 결과를 남겨둔다면 졸업을 못할 일은 없을 것이다. 우리 팀도 사실 결과물이 좋은 편은 아니다. 우리 팀은 전체적으로 이렇게 수행이 되었다.
A에 대해 개선을 생각하라 -> A가 개선된 버전이 업데이트될 예정임을 알았음 -> 상황을 바꿔 다른 것을 개선시켜보자 -> 문서화되지 않은 구현체가 있음 -> 방향을 틀어서 로그와 관련된 기능 추가
생각보다 마음대로 되진 않더라. 그리고 주제가 진행하다 보니 정말 마음에 들지 않아 의욕이 없어지는 점도 한 몫을 했다. 이렇듯 뭔가 잘 진행되진 않았지만, 이걸로 졸업 프로젝트를 인정받았고 졸업 요건을 채울 수 있었다. 졸프가 잘 진행되지 않아도 꾸준히 계속 진행하면 그래도 졸업은 할 수 있을거니 너무 불안해하진 말자.
졸프와 여러 필수 이수 강의들 봉사 등등을 수행해서 졸업 요건을 맞추면 조기졸업 신청이 가능할 것이다. 4-1은 널널하니 듣고 싶은 강의 몇 개 들으면서 남은 학점을 채우면 무난하게 졸업까지 가능할 것이다.
대학원 입시 준비 과정
이번에 나는 서울대학교 데이터사이언스대학원 석사과정으로 입학하게 되었다. 정형수 교수님 연구실에서 8월달부터 출근하게 되었다. 입시 준비부터 면접까지 한 번 얘기해보고자 한다.
석사과정 입시 준비
먼저 정량적인 학점부터 얘기하자면 나는 4.14/4.50(170명중 10등 근처되는 학점이다.)으로 대학원을 지원했다. 영어성적은 TEPS 357점이다. 입시 준비때부터 서울대학교를 생각해두고 있었기에 TEPS로 점수를 만들었다. TEPS 시험은 개인적인 생각으로는 수능 영어 1등급이나 토익 800점대면 충분히 327점을 넘길거라 생각한다. 유형을 알고가면 조금 도움이 되고 문제를 다 못풀어도 하나하나 정확하게 풀어서 점수를 올리는것이 좋다.
다른 특별한 것은 동아리 회장이나 문제 출제같은 경험이 있다는 것인데 음 뭔가 크게 영향을 주는 것인지는 잘 모르겠다. 주변 사례를 들어보면 우리 학교 기준으로 3.8을 넘기면 흔히들 말하는 대학원들에 그래도 서류를 합격할 수 있는 값은 되는 것으로 추정된다. 나는 후기 지원이라 (9월 입학) 전기보다 컷이 높다고 들었는데 실제로는 그렇게 크게 다르지는 않은 것 같다. 다만, 원하는 랩실에 진학할 확률은 아무래도 연구실 TO가 더 많은 전기가 높을 것이다.
일부 특수한 대학원들을 제외하면 랩이 지정되어야 대학원을 진학할 수 있다. 그렇기 때문에, “컨택”이라는 과정이 정말 중요한데.. 나같은 경우에는 두 곳에 컨택을 했다. 먼저 진학할 서울대학교 GSDS는 교수님께서 면접에 붙고 연락을 다시하라고 하셔서 입시 준비를 열심히 했다. 카이스트 랩(전산)에서는 가을학기 TO가 없다는 답을 받아서, 그나마 시스템 랩이 많은 전기및전자공학부로 원서를 썼다 (면접에 붙고 랩 컨택을 할 생각이었음). 원서를 쓰고 면접을 가서 붙는다고 하더라도 랩이 정해져야 되는데, 이게 가을학기는 TO가 없거나 정말 적어서 원하는 랩에 가기가 어렵다. 일단은 그래서 어찌 얼렁뚱땅 면접을 붙어보고 생각하자는 마인드로 준비를 했다.
서류는 둘 다 붙었었다. 서울대 면접이 더 빨라서 먼저 면접을 보러가게 되었다. 처음으로 면접을 본다고 정장이라는걸 사서 입고 갔는데, 생각보다 그렇게 풀로 입고 오진 않더라 (물론 꽤 있긴 했음). 혹시 면접보러갈 일이 있으면 그냥 셔츠에 단정한 바지같은거 입고가도 괜찮을거임. 사실 정장산다고 쓴 돈 좀 아까웠음 (언젠가는 입겠지만 공대생은 역시 후드티…)
서울대학교 면접 얘기를 자세히 해줄 수는 없지만, 나는 GSDS에서 면접으로 나올만한 주제를 예상해서 준비해갔다. 나는 그나마 비슷할 것으로 추정했던 카이스트 GSDS의 문제를 조금이나마 풀어보고 선형대수학이랑 확률통계론, 그리고 학부에서 배운 ML 모델들을 공부해서 갔다. 결론만 말하자면 공부해서 갔던게 도움이 됐었고 의외로 내가 열심히 했던 동아리활동이 면접에 꽤 도움이 됐었다. 사실 모집요강에 적혀있었던 것과 다르게 문제가 나와서 살짝 뭐지 싶었지만 어렵지 않게 풀 수 있는 문제들로만 구성되어 있어 괜찮았다. 문제를 풀고 설명하고 풀이를 다 설명하면, 면접에 들어오신 교수님들이 자소서에 적힌 내용에서 궁금하신걸 물어보시고 그냥 끄덕끄덕하시고 그대로 면접이 끝난다. 아마 문제를 잘 풀면 별 얘기 안하고 끝나는 그런 면접인듯.
그렇게 면접도 붙어서 교수님께 다시 연락을 드렸고 간단한 면담후에 도장을 받을 수 있었다! 서울대학교는 교수님의 도장을 받게되면 합격인 것으로 알고 있어서 그 이후에 카이스트는 면접도 가지 않았다. (아! 내 원서비!) 사실 교수님과 얘기가 잘 된 건 아마 랩실에 먼저 학부연구생으로 들어가 있는 누님께서 잘 얘기해줘서 그랬을 것이다. 감사합니다.. 감사합니다.. 그리하여 이번 8월부터 랩실에 출근하게 될 예정이다.
정말 얼렁뚱땅하고 입시가 끝났지만, 혹시라도 이걸보고 있는 대학원 지망인 후배가 있다면 하고 싶은 얘기가 있다. 컨택을 하려면 최소한 지원하기 한 학기전에는 연락을 드려보는 걸 추천한다. 연구실 TO가 내정된 사람들에게 돌아갈 수도 있어서 좀 텀을 두고 얘기를 해봐야 원하는 랩에 들어갈 확률이 좀 높아질 것이다. 특히, 가을학기는.. 봄학기에 TO를 모두 쓴 경우가 많아서 나처럼 거절 메일을 받을 경우가 좀 높다. 이걸 유의해서 미리미리 연락을 해보는 것이 좋다. 그리고 커뮤니티에 돌아다니는 학점얘기나 어떤 스펙 없으면 불가능 이런 얘기 별로 신빙성 높지 않은 것 같으니 소신껏 지원하면 좋겠다.
07 Sep 2023
- 한양대학교 컴퓨터소프트웨어학부 정형수 교수님의 2022년도 데이터베이스시스템및응용 강의를 듣고 정리한 내용임을 밝힙니다.
- 내용에 오류가 있을 수 있으며, 발견 시 댓글로 알려주시면 감사하겠습니다.
8. Architecture of DBMS
SQL은 어떻게 처리되는가?
DBMS는 어떤 단계를 거쳐서 SQL을 처리하는가? DBMS는 글자로 구성된 문자열을 받아서 해석하고 해석된 명령을 디스크에 읽고 쓰며 쿼리를 처리한다. 어떻게 시스템이 설계되었는 지 알아보며 처리과정을 이해해보자.
DBMS는 레이어 구조 아키텍쳐로 설계된 시스템이다. 레이어 구조란 어떤 기능을 담당하는 하나의 레이어가 다른 레이어와는 독립적으로 작용하면서 데이터를 받아 처리하는 구조이다. DBMS는 다음과 같은 레이어로 구성되어 있다.
1. Query Parsing & Optimization
Query Parsing & Optimization 레이어는 들어온 쿼리 스트링을 파싱하고 이를 분석해서 최적화해주는 레이어이다. 마치 컴파일러에서 소스코드를 읽어서 다른 언어로 변환하는 과정과 비슷하다. 이 레이어에서 DBMS가 읽을 수 있는 형태로 쿼리가 변환된다.
2. Relational Operators
Relational Operators 레이어는 쿼리를 처리하는 레이어이다. Union, Join 등의 관계 연산자들이 이 레이어에서 처리된다. 이 레이어에서는 쿼리를 처리하기 위해 레코드와 파일을 통해 위와 같은 어떤 하나의 dataflow가 실행된다.
3. Files and Index Management
테이블로 표현되는 데이터를 실제 논리적인 파일로 구성하는 파트이다. 이 레이어에서는 테이블을 파일로 저장하고, 파일을 버퍼에서 읽고 쓰는 등의 작업을 수행한다. 또한 인덱스를 관리하는 레이어이기도 하다. 보통 ‘page’라는 단위로 파일을 관리하고, 파일이 페이지라는 단위로 나뉘어져 각각 데이터가 저장된다. 이 레이어의 행위는 모두 버퍼 레이어를 통해 전달된다.
인덱스라는 말이 나왔는데, DBMS에서 인덱스란 내부적으로 사용하는 B+Tree에 작성되는 인덱스를 의미한다. B+Tree는 이후에 자세히 다루도록 하겠다. B+Tree의 노드는 인덱스의 순서대로 관리되기 때문에, 정렬이 되어있다는 특성을 가지고 있어 효율적인 탐색이 가능하게 해주낟. 이렇게 B+Tree를 통해 인덱스를 관리하는 레이어가 바로 Files and Index Management 레이어이다.
그림을 참고하자면, 아래의 테이블을 실제로 저런 느낌의 논리적인 파일 형태로 바꾸어 저장하게 해주는 레이어이다. (여담으로 DBMS 구조에 대해 가르치는 강의들은 이걸 보통 B+Tree를 구현하는 것을 과제로 내는데 우리학교는 이 과목이 한때 2학년에 있었다. 그래서 학년에 맞지 않는 과제를 한다고 다들 고생했다. 물론 정형수 교수님 강의 과제는 이게 시작에 불과했다.)
4. Buffer Management
버퍼가 무엇일까? 메모리(RAM)에 저장되는 어떤 데이터 공간이다. DBMS는 디스크에 저장되어 있는 데이터를 메모리에 올려서 처리한다. 이 때, 그 데이터들을 위해 할당된 공간이 바로 버퍼이다. 버퍼가 왜 필요할까?
하드디스크와 같은 물리적 저장 매체들은 읽고 쓰는 속도가 메모리에 비해 아주 많이 느리다. 일반적인 하드디스크는 물리적으로 회전하며 데이터를 읽는 구조이다. 원통 모양의 판이 계속 회전하며 디스크 헤드가 읽어오는 방식이라 전자적으로 동작하는 CPU에 비해 아주 느리다. 보통 연산을 처리할 때, 하드디스크 -> 메모리 -> CPU 순서로 데이터를 읽어서 처리하게 된다. 이렇게 하는 이유는 메모리라는 공간을 둠으로써 하드디스크의 아주 느린 R/W 성능을 보완하고 빠르게 데이터를 올려 연산하기 위해서이다. 하드디스크쪽으로 갈 수록 용량이 아주 커지지만 속도가 느려지고 반대로 갈 수록 용량은 작아지지만 속도가 매우 빨라진다. 이런 특성을 가지고 있어서 CPU가 빠르게 데이터를 처리하는 동안에 하드디스크에서 버퍼에 데이터를 올려놓으면 더욱 효율적인 처리가 가능하게 되는 것이다.
이런 이유로 DBMS는 R/W 성능 향상을 위해 버퍼 레이어를 가지고 있다. 버퍼 레이어는 DBMS가 작동하기에 필수적인 기능을 하는 레이어는 아니다. 단지, 성능 향상을 위해 존재하는 레이어이다. 즉, 버퍼 레이어가 없어도 DBMS는 작동할 수 있다 (아주 느릴뿐..)
DBMS가 실행하는 동안 램에 일정량의 공간을 형성해 미리 DB 페이지들을 옮기고 거기서 읽고 쓰기 작업을 하게 한다.
5. Disk Space Management
실제로 디스크에 읽고 쓰는 작업을 해주는 레이어다. 즉, 가장 하위에 위치하는 레이어이고 가장 많은 코스트가 드는 레이어이다. Disk I/O는 아주 많이 느리다. 극단적으로 예를 들면, CPU와 메모리 사이의 거리는 100km 정도이고 메모리와 디스크 사이의 거리는 지구로부터 명왕성까지의 거리이다. 즉, 아주 성능 차이가 심하고 디스크에 읽고 쓰는 작업이 아주 느리다는 것을 생각할 수 있다.
Disk I/O의 코스트가 아주 크기 때문에 버퍼 레이어를 통해 데이터를 주고 받게 된다. 즉, 버퍼에 적힌 내용을 디스크에 쓰게 되고, 버퍼에 필요한 페이지를 찾아 올려주는 역할을 한다. Disk I/O와 관련된 시스템 콜들(read, write, seek 등등..)을 사용해 구현할 수 있다.
06 Sep 2023
- 한양대학교 컴퓨터소프트웨어학부 정형수 교수님의 2022년도 데이터베이스시스템및응용 강의를 듣고 정리한 내용임을 밝힙니다.
- 내용에 오류가 있을 수 있으며, 발견 시 댓글로 알려주시면 감사하겠습니다.
7. Advanced SQL
View
쿼리 결과를 두고두고 꺼내쓰고 싶을 때가 있다. View는 그런상황에 사용하기 좋은 기능이다. View는 가상의 테이블을 저장하는 강력한 기능을 제공한다. 가상이라는 말이 붙는 이유는 쿼리 결과 데이터 자체를 어디에 저장하는게 아니라 View를 사용하면 그때마다 쿼리를 실행해 데이터를 돌려주기 때문이다. 즉, 저장되는게 쿼리문 자체라고 생각하면 좋다.
View 생성
CREATE VIEW view_name
AS SELECT columns
FROM table
WHERE condition;
이런 식으로 View를 생성하고 이름을 지정하면 AS 뒤의 쿼리문이 저장된다. 이걸 가상 테이블이라고 하는만큼 테이블처럼 사용할 수 있다.
View 사용
SELECT *
FROM view_name
WHERE condition;
이런식으로 또 다른 쿼리를 날릴 수도 있는 것이다. 서브쿼리를 날리는 것처럼 사용할 수 있고, 테이블처럼도 사용할 수 있다. 다만, View가 가상 테이블인 이유로 삽입 삭제 등은 연산이 제한될 수도 있다. View는 삭제하지 않는 이상 계속 남아있기 때문에 DROP을 통해 삭제할 수 있다.
View 삭제
이렇게 쿼리를 작성하면 View가 삭제된다.
With (Common Table Expression)
With는 쿼리 결과를 저장하는 기능을 제공한다. 음? 그럼 View랑은 뭐가 다를까. With는 마치 변수처럼 동작한다. 그 말은 즉슨, 쿼리문 내에서만 결과가 살아있다. 즉, View와 가장 큰 차이점은 쿼리문이 종료되면 With로 생성된 쿼리 결과는 사라진다 점이다.
With 사용
WITH with_name AS (
SELECT columns
FROM table
WHERE condition
)
SELECT *
FROM with_name
WHERE condition;
이 쿼리문이 종료되고 나서 With문에서 작성한 이름을 가지고 사용하면 오류가 발생한다. 쿼리가 종료되고 나서 사라졌기 때문이다. 임시 테이블 정도로 이해하면 될 것 같다.
중복 With
With로 정의한 결과값을 또 사용할 수 있다.
WITH with_name_1 AS (
SELECT columns
FROM table
WHERE condition
),
with_name_2 AS (
SELECT columns
FROM with_name_1
WHERE condition
)
SELECT *
FROM with_name_2
WHERE condition;
이런식으로 정의한 결과값을 또 다른 With문에서 사용할 수도 있다.
Inner Join
이전 글을 읽고 왔으면 Join은 알고 있을 것이다. 그럼 Inner Join은 무엇일까? 기본적으로 사용하는 Join이 바로 Inner Join이다. 즉, Join이라고 하면 일반적으로는 Inner Join을 말하는 것이다. Inner가 있으면 Outer도 있을 것 같다고 생각했다면 정답이다. Inner Join부터 알아보자.
Inner Join은 두 테이블 간 Join 조건을 동시에 만족하는 레코드만 반환하는 조인이라 생각하면 된다. 정말 당연하게 사용하면 된다. Inner라는 것을 명시하기 위해서는 다음과 같이 작성하면 된다.
SELECT *
FROM table1
INNER JOIN table2 ON table1.column = table2.column;
여기서 Inner는 생략 가능하고, table1과 table2의 column이 같은 것만 들고 오는 것이다. 평범한 Join이다.
Outer Join
Outer Join은 조건을 만족하지 않아도 살려주는 Join이다. Left Outer Join과 Right Outer Join, Full Outer Join이 있다. 각각 왼쪽, 오른쪽, 양쪽 테이블을 기준으로 조인을 수행한다. 무슨말일까?
Left Outer Join
왼쪽 테이블 데이터를 모두 가져온 뒤에 오른쪽 테이블 데이터와 조건을 비교한다. 조건을 만족하지 않는 데이터는 NULL로 채워서 반환한다. 이게 Left Outer Join이다. 즉, 조건을 만족하는 것을 찾되 데이터를 날리지 않고 싶을 때 사용하는 쿼리이다.
SELECT a, Y.b
FROM X
LEFT OUTER JOIN Y
ON X.a = Y.a;
이런식으로 사용하면, X 테이블의 값을 모두 가져오고 Y 테이블의 값과 조건을 비교한다. X.a = Y.a를 만족하지 않는 레코드는 Y.b값이 모두 NULL로 반환된다. RIGHT OUTER JOIN
이라고 명시하면 된다.
Right Outer Join
Left Outer Join과 방향만 반대가 된다고 생각하면 된다.
Full Outer Join
Cartesian Product를 반환한다. 즉, 두 테이블의 모든 레코드를 조합해서 반환한다. 물론 조건을 만족하지 않으면 NULL로 반환하게 된다. FULL OUTER JOIN
이라고 명시하면 된다.
Another..
이외에도 with recursive 같은 쿼리나 rollup 같은 것도 있지만, Advanced Query는 여기서 마무리하고 SQL 글은 이제 끝내도록 하겠다. 다음 글부터는 DBMS의 설계와 구현을 다룰 예정이다.
요약
- View: 가상 테이블. 쿼리문을 저장하는 기능. 테이블처럼 사용할 수 있다.
- With: 쿼리 결과를 저장하는 기능. 변수처럼 사용할 수 있다.
- Inner Join: 두 테이블 간 Join 조건을 동시에 만족하는 레코드만 반환하는 조인
- Outer Join: 조건을 만족하지 않아도 값이 사라지지 않는 Join. Left, Right, Full Outer Join이 있다.
05 Sep 2023
어플리케이션 개발
연구실에 만들어져 있던 어플리케이션을 유지 보수하고 기능 몇개 추가하는 작업을 해본게 다였는데, 요청을 받아서 새로 어플리케이션을 개발하게 되었었다. 어플리케이션 이름은 ‘내손에 치매안심주치의’이다. 치매안심센터와 협약된 병원들과 연결을 도와주고 연락처 정보 등을 제공해주는 간단한 어플리케이션이다. 디자인을 포함해 기획된 내용이 다 정해져 있어서 나는 그대로 만들면 되는 간단한 작업이었다. 할 줄 아는게 React Native 밖에 없었기 때문에 RN으로 개발을 했다. 사실 원래 다른 분이 네이티브로 개발하다 중단한 파일이 있었는데, 코틀린을 배우는 러닝 커브가 더 클 것 같아서 새로 RN으로 개발했다.
개발 환경
React Native에 Expo를 사용해 개발했다. 단순히 병원 리스트와 병원 위치만을 알려주는 기능만 필요했기에 따로 서버없이 프론트로만 처리하게 개발을 진행했다. 프론트 내부에서 DB를 사용해 병원 리스트를 관리하고자 expo-sqlite를 사용해 직접 쿼리를 날리며 관리하는 식으로 개발했다.
개발 과정
처음엔 디자인된 페이지를 옮기고 라우팅 작업을 먼저 했다. 페이지가 3개밖에 없는 어플리케이션이라 금방 끝났다. 요청에 따라 랜딩 페이지를 3초간 보여주고 메인 페이지로 이동하게 했고, 메인 페이지에서 권역별로 병원리스트를 보는 상세페이지로 들어가는 구조이다. 지역이 4개가 있었는데, 라우팅 파라미터로 권역명을 전달하게 해서 하나의 페이지가 4개의 권역을 컨트롤할 수 있도록 디자인했다.
그 다음으론 지도를 띄우는 부분을 구현했다. react-native-maps를 사용해 구글 지도를 띄우도록 했다. 원래는 카카오 맵을 사용하려 했는데(무료라서..) expo를 사용중이다 보니 sdk를 사용하기 어려웠고, 웹뷰를 사용해 지도를 띄워야했다. 웹뷰를 사용하다 보니 개발이 복잡해져서 구글 지도를 사용하는 것으로 변경했다. Maps SDK for Android를 사용하고 단순히 맵을 로드하는 비용은 무료다.
react-native-maps를 사용하는데 생각보다 문제가 있어서 지도를 띄우는데 조금 시간이 걸렸다. 사유는 오타.. 오타가 생겨서 API키가 제대로 안들어가서 그랬었다. API키가 제대로 들어가니 화면이 잘 떴다. 내 위치를 지도에 표시해주고, 이제 남은건 병원들의 위치를 표시해주는 것이었다.
DB를 쓰기 위해선 DB를 만들고 테이블을 만들어야했다. 테이블은 병원 이름, 주소, 전화번호, 위도, 경도를 저장할 수 있도록 만들었다. 그런데, 데이터가 .csv고 이걸 파싱해서 DB로 만들었었다. 그리고 이 sqlite db파일을 assets에 넣어서 쓰려고 했는데, 이게 안드로이드 보안 문제 등등 해서 쌩으로 넣는게 어려웠다. 그래서 그냥 .csv 파일을 넣어두고 expo-file-system을 사용해 파일을 읽어와서 어플리케이션 안에서 db를 만들고 테이블을 만드는 것으로 구현했다. 그래서 지금 데이터 변경을 하려면 이 .csv파일을 수정하고 빌드하면 알아서 바뀌게끔 되어있다.
먼저 권역별로 리스트를 얻어오는 쿼리를 작성해야했다. 권역별로 병원들이 나뉘어져 있었는데, 데이터에 권역명은 적어두지 않아서 LIKE 쿼리로 주소에 지역명이 존재하는 지 체크하는 것으로 구현했다. 병원 데이터에는 주소만 존재했고 위도나 경도는 없었다. 그래서, 테이블에는 위도와 경도를 추가해 쉽게 병원 위치를 나타내게 만들었다. 병원 리스트 수가 별로 되지 않고 변동이 되는 정보가 아니었기에 수작업으로 위도와 경도를 구해 데이터에 추가했다. 테이블에 해당 병원이 속한 지역명으로 쿼리를 날려 해당되는 정보만 마커로 지도에 찍어줬고, 즐겨찾기 기능도 칼럼 하나 추가해서 구현했더니 개발이 끝났다.
개발 후기
간단한 형태의 어플리케이션 개발이었는데, 내가 기획한 어플리케이션은 아니지만 만든 앱이 기사도 나오고 해서 신기했다. GCP에서 API 사용 찍히는걸 보면 사용량이 꾸준히 올라가는것도 신기하고 이걸 정말 사용하고 있구나라는게 느껴진다. 플레이 스토어에 올리려면 필요한 절차들도 배웠고, 크게 느낀건 expo라는 플랫폼이 정말 앱을 제대로 개발하고자 하면 한계가 많다는 것도 체감했다. 특히, expo를 사용하면 쓰기 껄끄로운 라이브러리들이 많아서 편하게 개발하려고 쓴 플랫폼인데 오히려 제약을 받는 느낌이었다. 그리고 expo로 빌드한 결과물이 테스트할 때와 다른 경우도 종종 있었다. 그래서, 어딘지 대충 짐작하고 수정하고 빌드해서 확인하는 경우가 있었는데.. 이 부분이 정말 별로였다. Flutter가 Dart라는 자기들만 쓰는 … 언어로 개발해야하는 프레임워크인데다 구글이 프로젝트를 포기하면 사라질 생태계니까 영 관심이 없었는데, RN을 쓰면 쓸수록 별로인 부분이 많아서 오히려 관심이 생긴다. 물론, 앱개발을 좋아하진 않아서 배울 지는 미지수다.
31 Aug 2023
- 한양대학교 컴퓨터소프트웨어학부 정형수 교수님의 2022년도 데이터베이스시스템및응용 강의를 듣고 정리한 내용임을 밝힙니다.
- 내용에 오류가 있을 수 있으며, 발견 시 댓글로 알려주시면 감사하겠습니다.
6. Aggregation & Group By
Aggregation
집계 함수는 어떤 테이블의 데이터를 가지고 하나의 값을 만들어내는 함수를 의미한다.
어떤 테이블의 레코드 수를 세고 싶으면 COUNT를 사용할 수 있고, 합을 나타내려면 SUM을 사용하면 된다. 이외에도 AVG, MAX, MIN 등의 여러 집계 함수들이 존재한다.
COUNT
별표는 모든 칼럼을 의미한다. 따라서 위의 쿼리는 A 테이블의 레코드 수를 세는 것이다.
오호, 그럼 아무 칼럼이나 넣어도 같은 값이 아닌가? 하는 생각을 할 수 있는데 특정 칼럼에 NULL이 존재하면 해당 레코드는 제외하고 센다. 따라서, COUNT(*)와 COUNT(칼럼)은 다른 결과를 보일 수 있다. COUNT가 적용되는 시점은 5장에서 얘기했듯 WHERE 절이 적용된 이후이다. 따라서, 어떤 쿼리의 결과에서 COUNT를 센다고 생각하면 된다.
SUM
SELECT SUM(column)
FROM A;
COUNT 이외에는 모두 단일 칼럼에만 적용된다. 모든 레코드의 해당 칼럼 값을 더해서 반환한다.
AVG
SELECT AVG(column)
FROM A;
MAX
SELECT MAX(column)
FROM A;
MIN
SELECT MIN(column)
FROM A;
Group By
어떤 제품의 개수를 그룹별로 알고 싶을 때 어떻게 해야할까? 테이블을 Product(name, date) 라고 하자. 각각 제품 이름과 제품 생산 일자이다. name별로 개수를 알고 싶다고 생각해보자. 이런 상황에서 Group by를 사용할 수 있다.
SELECT name, COUNT(*)
FROM Product
GROUP BY name;
음.. 뭐가 어떻게 묶이는 건지 잘 모르겠다. 다음 예제를 보자.
name이 같은 레코드들을 묶어서 값을 한 번에 나타내는 것으로 이해할 수 있다.
즉, GROUP BY는 특정 칼럼을 기준으로 레코드들을 묶는 것이다. 두번째 과정에서 GROUP BY로 그룹이 생기고 마지막에 projection이 적용되며 count 결과를 얻게 된다.
Having
Aggregate에 제약을 거는 것으로 간단하게 설명할 수 있다.
만약 count가 2 이상인 것만 보고 싶다면 다음과 같이 하면 된다.
SELECT name, COUNT(*)
FROM Product
GROUP BY name
HAVING COUNT(*) >= 2;
즉, GROUP BY 이후에 HAVING이 적용된다고 생각할 수 있다. 이후 projection이 적용된다.
쿼리 실행 순서?
실제 실행 순서는 이와 다를 수 있지만, 의미상 실행 순서는 다음과 같다.
FROM -> WHERE -> GROUP BY -> HAVING -> SELECT
Projection이 마지막에 적용되는 것을 생각하면 생각보다 헷갈리지 않으니 참고하자.
요약
- 집계 함수는 테이블의 레코드를 가지고 하나의 값을 만들어내는 함수이다.
- GROUP BY는 특정 칼럼을 기준으로 레코드들을 묶는 것이다.
- GROUP BY 이후에 HAVING이 적용된다고 생각할 수 있다. 이후 projection이 적용된다.
- 실행 순서는 FROM -> WHERE -> GROUP BY -> HAVING -> SELECT 이다.