티스토리 뷰

Log/.TIL

[TIL]180613-0617

가그린민트 2018. 6. 17. 23:20


1. batch

no update 그리고 join문을 최대한 없애더라도 대규모 데이터 INSERT에 대한 고민과 DB scale out와 관련하여 persistence랄까 messaging architecture에 대한 고민은 여전히 남는다. 우선 지금의 프로젝트는 메시징까지는 고려할 필요는 없으나 대규모 데이터 INSERT가 예상되었고, 팀 내에서 아직 mybatis를 사용하고 있는터라, 이를 기준으로 고민해보았다.

결론은 mybatis의 executor-type을 batch로 하고, insert문 하나로 처리하되 이 때 values를 일정 단위로 잘라서 보내는 것이 가장 효율적이란 생각이 들었다. 그 외 이전까지 구현해야 했던 SqlSessionTemplate 및 Factory 등은 mybatis-spring-boot-starter에 내장되어 있다. 

사실 LOAD INFILE 방식도 고려했었는데, mybatis에서 지원하지 않아 jdbc로 직접 구현해보기도 했으나 DB는 scale out, 부하분산 등을 고려하면 카탈로그db로만 쓰는 것이 좋겠다는 의견에 제외하였다. 처음에 row별로 여러 데이터들에 대한 비교로직이 있어 시간이 오래걸렸고 이에 sqs 등을 통해 큐잉하여 동시성있던 배치성 작업 방식이 이제 시간도 단축되고 아키텍처도 단순하게 바뀌었으며 비동기적인 처리가 가능해졌다는 점에 나름의 소득이 있던 프로젝트였다. 

# http://pstree.tistory.com/115
# https://kgmyh.github.io/blog/2017/12/22/Mybatis-SpringBoot/
# 이미 알고 있듯이, mybatis를 스프링과 함께 사용하기 위해서는 최소한 한개의 SqlSessionFactory와 최소한 1개의 매퍼 인터페이스가 필요하다.
# mybatis-spring-boot-starter는 다음과 같은일을 처리한다.
# 존재하는 DataSource 자동감지
# SqlSeessionFactoryBean을 사용해서 해당 데이터소스를 전달하는 SqlSessionFactory의 객체를 생성하고 등록한다.
# SqlSessionFactory을 이용해 SqlSessionTemplate의 객체를 생성하고 등록한다.
# 매퍼들을 자동스캔한 뒤 스캔된 것들을 SqlSessionTemplate에 연결하고 Spring Context에 등록해서 당신의 빈들에 주입할 수 있게 해준다.
# application.yml
mybatis:
config-location: classpath:mybatis-config.xml
executor-type: batch
# Service layer
@Async("threadPoolTaskExecutor")
@Transactional
public void save(List<Map> list, Map map) {
...
for (int i = 0; i < list.size(); i += CHUNK) {
slice(map, list, i);
dao.save(map);
}
...
}
private void slice(Map map, List list, int i) {
int next = i + CHUNK;
if (next > list.size()) next = list.size();
map.put("list", list.subList(i, next));
}
# dao
public void save(Map map) {
this.sqlSession.insert("sample.mybatis.mapper.save", map);
}
# xml
<insert
id="save"
parameterType="hashmap"
flushCache="true"
statementType="PREPARED"
>
INSERT IGNORE INTO table_name (idx, regdate, `key`) VALUES
<foreach collection="list" item="item" separator=", ">
(UUID(), CURRENT_TIMESTAMP, TRIM(#{item.key}))
</foreach>
</insert>


2. git flow 

http://brainbackdoor.tistory.com/87


3. SQL 데이터 가공 연습

#### 증감 표현
SELECT
SIGN(q2 - q2) FROM ...
/* 양수라면 1, 같으면 0, 음수라면 -1을 리턴 */
#### 최대/최소값 찾기
SELECT
GREATEST(q1, q2, q3, q4)
, LEAST(q1, q2, q3, q4)
FROM ...
#### 평균값 구하기

SELECT
(COALESCE(q1, 0) + COALESCE(q2, 0) + COALESCE(q3, 0) + COALESCE(q4, 0))
/ (SIGN(COALESCE(q1, 0)) + SIGN(COALESCE(q2, 0)) + SIGN(COALESCE(q3, 0)) + SIGN(COALESCE(q4, 0))) AS average
FROM ...
#### 두 값의 거리 계산하기
SELECT
ABS(x1 - x2) AS `abs`
, SQRT(POWER(x1 - x2, 2)) AS rms
FROM location_1d
SELECT
SQRT(POWER(x1 - x2, 2) + POWER(y1 - y2, 2))AS dist
FROM location_2d
#### RANK

DROP TABLE IF EXISTS popular_products;
CREATE TABLE popular_products (
product_id varchar(255)
, category varchar(255)
, score numeric
);
INSERT INTO popular_products
VALUES
('A001', 'action', 94)
, ('A002', 'action', 81)
, ('A003', 'action', 78)
, ('A004', 'action', 64)
, ('D001', 'drama' , 90)
, ('D002', 'drama' , 82)
, ('D003', 'drama' , 78)
, ('D004', 'drama' , 58)
;
/* ORACLE 혹은 MySQL 8.0이상 */
ROW_NUMBER() OVER(ORDER BY score DESC) AS row
, RANK() OVER(ORDER BY score DESC) AS rank
, DENSE_RANK() OVER(ORDER BY score DESC) AS dense_rank -- 같은 순위의 경우 처리
-- 현재 행보다 앞에 있는 행의 값 추출
, LAG(product_id) OVER(ORDER BY score DESC) AS lag1
, LAG(product_id, 2) OVER(ORDER BY score DESC) AS lag2
-- 현재 행보다 뒤에 있는 행의 값 추출
, LEAD(product_id) OVER(ORDER BY score DESC) AS lead1
, LEAD(product_id, 2) OVER(ORDER BY score DESC) AS lead2

https://dev.mysql.com/doc/refman/8.0/en/window-function-descriptions.html
이 함수들과 집약 함수를 조합하면 굉장히 많은 부분들을 하나의 쿼리에서도 효율적으로 수행 가능해진다.
얼른 MySQL 8.0 환경을 구성하던가.. 아니면 embulk를 활용해서 빅쿼리로 테스트해봐야겠다.
(-> 빅쿼리에서 안됨 ㄷㄷ AWS EMR로 해봐야 하나.. ORACLE은 도무지 설치하기가 싫다)
SELECT
product_id
, score
, rank
, real_rank AS dense_rank
FROM
(
SELECT
product_id
, score
, ( @rank := @rank + 1 ) AS rank
, ( @real_rank := IF ( @last > score, @real_rank:=@real_rank+1, @real_rank ) ) AS real_rank
, ( @last := score )
FROM popular_products
JOIN ( SELECT @rank := 0, @last := 0, @real_rank := 1 ) AS b
ORDER BY `score` DESC
) AS a
#### 열로 표현된 값을 행으로 변환하기
DROP TABLE IF EXISTS quarterly_sales;
CREATE TABLE quarterly_sales (
year integer
, q1 integer
, q2 integer
, q3 integer
, q4 integer
);
INSERT INTO quarterly_sales
VALUES
(2015, 82000, 83000, 78000, 83000)
, (2016, 85000, 85000, 80000, 81000)
, (2017, 92000, 81000, NULL , NULL )
;
SELECT
q.year
, CASE
WHEN p.idx = 1 THEN 'q1'
WHEN p.idx = 2 THEN 'q2'
WHEN p.idx = 3 THEN 'q3'
WHEN p.idx = 4 THEN 'q4'
END AS `quarter`
, CASE
WHEN p.idx = 1 THEN q.q1
WHEN p.idx = 2 THEN q.q2
WHEN p.idx = 3 THEN q.q3
WHEN p.idx = 4 THEN q.q4
END AS `sales`
FROM quarterly_sales AS q
CROSS JOIN
(
SELECT 1 AS idx
UNION ALL SELECT 2 AS idx
UNION ALL SELECT 3 AS idx
UNION ALL SELECT 4 AS idx
) AS p


4. 킁

차주부터 구글 전문팀과 gtm, optimizer 등에 대한 교육이 진행될 듯한데.. ga는..? 다음 프로젝트는..? 리팩토링/이펙티브자바/spring/JPA는..? 데이터 플랫폼(spark, kafka, hadoop, hdfs, elsaticsearch, drill)은 언제..? 보안기사 실기 준비는 가능한건가? 네떡 책은 언제 다읽지 ? 살은 언제 빼지? 읽어야 할 것들도 제법 되는데? 틈틈히 View JS 하고나서 모두의학원 프로젝트 완결이나 지을까했는데.. 아 그러고보니 영어회화 레벨테스트하라고 메일도 왔던데.. 상반기에 한번은 소개팅하겠거니 했는데 벌써 6월도 끝났네.. 야간 대학원을 가려고 하는데.. 주말에 하는 꼴을 보니 괜히 일벌이는거 아닌가 싶다.

동시성처리하기엔 배치 잡 대기열이 너무 길 것 같고.. 병렬 진행하기에는 ThreadPool이.. 안습이네

그래도 이번주는 코딩하는게 꽤 재미있었다. 다소 처리할 작업들이 겹쳐져 Service layer가 지저분해지면서 헤맸었는데 테스트를 짜가면서 단위들을 쪼개다보니 코드도 개선되고 문제도 해결되었다. 일상도 리팩토링이 필요한 시점인가..


5. 흠

올해 지젝의 저서를 한권 읽으려고 했는데, 마침 신부님과 대화중에 책 한권이 언급되었다. 해서 도서관에 갔다가 다른 책을 빌렸다(?) 바우만과 지젝, 그리고 거대한 전환의 오마주인듯한 '거대한 후퇴'..


6. 읭

'A는 B, 혹은 input에 따른 output이 나오는, 그런 예상가능한 신이었다면 믿지 않았을 것이다.

종교란 삶을 살아가면서 체험되는 것이기 때문에 신비로운 것 같다.'


이야기 해놓고도 클리셰덩어리라는 생각이 들어 마무리지으려는데.. 이내 나온 감탄사는 무엇..

그런 순간들이 있다. 

지나가는 말에 자지러지며 웃고는 되려 왜 나보고 무표정이냐는 사람들.

그냥 '툭' 던져놓은 것들이 제각기 친절, 배려 등으로 포장되는 경험들.

미성숙한 것인지 나이가 들어버린 것인지 알 수 없게되어버린 요즈음, 여러 사건들이 일상을 더이상 편린에 머물게하지 않는다. 익숙했던 것들이 낯설어지는 순간, 그렇게 경계인이 되버리고 만다.

'Log > .TIL' 카테고리의 다른 글

[TIL]180619  (0) 2018.06.19
[TIL]180618  (0) 2018.06.18
[TIL]180611-0612  (0) 2018.06.12
[TIL]180608  (0) 2018.06.08
[TIL]180606  (0) 2018.06.06
댓글
링크
최근에 달린 댓글
«   2024/04   »
1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30
Total
Today
Yesterday