서론

지금까지 별생각없이 insert statement를 써왔다. 되게 오래걸리는 작업, 크론에서 돌아가야할 애들인 경우에만 의식적으로 bulk insert를 썼다.('bulk' 라는 말 때문이었을까? 뭔가 대용량인 경우에만 써야할 것 처럼 느껴졌다.)

최근 내가 만든 부분에서 에러로그가 자주 올라오면서 우리 센터장이신 분이 나에게 찾아와 질문하시길... 

for문 돌면서 insert해요, 아니면 statement 만들어서 insert 해요?

나는 당당하게! for 돌면서 insert하고 있슴디다^-^ 문제 없습니다. 했는데 문제가 있다고 한다. '엔지니어'라는 직함을 달고있다면 어떤 원리인지 찾아보아야 했을텐데 잘 몰랐어서, 그리고 찾아볼 생각도 없었어서 ㅠ 이제라도 다시 찾아본다. 


본론

역시 가장 정확한 정보는 만든 사람들의 가이드가 아니겠는가. insert vs bulk insert와 같은 키워드로 googling을 해보니 쉽게 찾을 수 있는 링크! 내용 중 중요하다고 생각되어지는 부분들을 가지고와 번역해본다. 

https://dev.mysql.com/doc/refman/8.0/en/insert-optimization.html


Optimizing INSERT Statements 

insert 문을 최적화 하기

To optimize insert speed, combine many small operations into a single large operation. Ideally, you make a single connection, send the data for many new rows at once, and delay all index updates and consistency checking until the very end.

insert속도를 최적화하기 위해서는, 여러개의 작은 연산을 하나의 큰 연산으로 합쳐라. 이론상으로, 하나의 커넥션을 만들고, 한번에 다수의 행에대한 데이터를 보내고, 모든 index 업데이트,  consistency checking(무결성 체크?)를 끝날때까지 지연시킨다. 


The time required for inserting a row is determined by the following factors, where the numbers indicate approximate proportions:

한 행을 insert하는데 필요한 시간은 다음과 같은 요인들에 의해서 결정된다. 숫자는 대락적인 비율을 뜻한다. 

Connecting: (3)

Sending query to server: (2)

Parsing query: (2)

Inserting row: (1 × size of row)

Inserting indexes: (1 × number of indexes)

Closing: (1)

If you are inserting many rows from the same client at the same time, use INSERT statements with multiple VALUES lists to insert several rows at a time. 

만약 동일한 클라이언트에서 동시에 여러 행들을 insert하고 있다면, 한번에 여러 행을 insert하도록 insert문을 VALUES 리스트랑 같이 사용해라.

This is considerably faster (many times faster in some cases) than using separate single-row INSERT statements. 

이것은 분리된 한행의 insert문을 사용하는 것보다 상당히 빠르다. 



결론

사소한 것일지라도, 내가 만든 것이 어떻게 되어있는지 알고 넘어가야겠다는 생각이 들었다. 내가 만든 부분은 한 클라이언트에서 동시에 약 10번의 insert가 개인당 이뤄졌었다. 5000명이 들어왔다고 하면 50000번의 insert가 있었던 거였는데 이걸 2번의 insert로 줄일 수 있었다. 그러면 총 10000번의 insert로 오분의 일로 커넥션을 줄일 수 있었따. 히이익. 자주 몰리는 부분들에 대해 조금 더 고민해 볼 것. 그리고 트랜잭션 레벨에 대해서도 고민해볼 것. 고민할 것이 투성이다. 


'개발개발 > mySql' 카테고리의 다른 글

DB를 쿼리로 업데이트 할때  (0) 2018.09.16
mysql 월/주차 구하기  (0) 2018.01.06
left join 시 속도 문제  (0) 2016.12.20
SELECT 정렬하기 정리  (0) 2016.12.13
order by varchar to int  (0) 2016.11.24

일을 하다보면.. 그러기 싫지만 강제로 DB에 접속해서 쿼리로 업데이트를 해야할때가 많다.

그럴때마다 나는 그냥 쫄아있는 상태로 손을 벌벌 떨면서 ... update table set column = 0 where flag = 1; 과 같은걸 날리고 데이터를 확인하고는 했다.

하지만 그럴때 덜 쫄 수 있는 방법이 있다. 방법은 트랜잭션을 사용하는 것이다. 

R을 제외한 CUD를 칠때는 다음과 같은 방법을 쓴다.

1. 정상적으로 작업했을 때 나오는 카운트 수를 본다. 

select count(*) as c from table where flag = 1;

그럼 쿼리가 실행되면서 몇건인지가 나온다. 그 몇 건을 봐둔다. 

2. 다음과 같은 문구를 미리 작성해둔다. 주석도 포함해서

# start transaction;

# update table set column = 0 where flag = 1; 

# rollback;

# commit;

3. 주석을 하나씩 풀어가면서 진행한다. 우선 트랜잭션을 실행시킨다. 

start transaction; (실행)

# update table set column = 0 where flag = 1; 

# rollback;

# commit;

4. 원래 돌리려고 했던 업데이트 문 실행
update table set column = 0 where flag = 1; 

5. 이때 affected rows가 맨 첨에 날린 카운트수와 일치하는지 본다. 시간 차이가 있겠으나 뭐 얼추 비슷한 값이 나올것이다. 

6. 만약 이상함을 감지했다면 당황하지 않아도 된다. rollback 시키기

rollback;

이렇게 하면 내가 update문을 치기 전으로 돌아간다. 트랜잭션을 걸어놓았으니까 말이다. 

7. 정상적이었다면? commit하기!

commit;을 실행시켜준다. 그러면 끝이당.

'개발개발 > mySql' 카테고리의 다른 글

insert와 bulk insert 무엇을 써야할까요?  (1) 2018.10.04
mysql 월/주차 구하기  (0) 2018.01.06
left join 시 속도 문제  (0) 2016.12.20
SELECT 정렬하기 정리  (0) 2016.12.13
order by varchar to int  (0) 2016.11.24

서론

월/주차 별로 통계를 내야하는 페이지가 있었다. 

내가 만들고 싶었던 것 =  11월 4주차, 11월 5주차 와 같이 월/주차를 구해서 표현하고, 통계를 내고 싶었다.


첨에는 week() 함수, weekofyear()함수를 사용해서 group by 해서 통계페이지를 냈다. 

그런데 52, 27등으로 표현되는 주차를 어떻게 12월 5주차, 1월 2주차 등으로 보여줄지 모르겠어서 (조금) 헤맸다.

막 꼬여가지고 13월 1주차 나오고 그랬다.. 


결론은 

이렇게 짰다.

월 구하기

월은 month()를 이용해서 구할 수 있다.
select month(구하고자 하는 날짜 컬럼) from 테이블;

주차 구하기

주차는 weekofyear()를 사용해서 구할 수 있다. 
다만, 내가 원하는 주차는 단순히 '53주차' 가 아니라 12월 28일이 12월의 4주차인지 5주차인지 1주차인지에 해당하는 것이었다. 그래서 다음과 같이 쿼리를 짰다.
select weekofyear(구하고자 하는 날짜) - weekofyear(구하고자 하는 달의 첫째날) + 1 from 테이블

요런식으로 weekofyear(대상 날짜) - weekofyear(해당 달의 첫째날) + 1(해당 날짜의 주차 - 해당 달의 첫째날 의 주차 + 1) 로 계산하면 문제없이 원하는 m주차를 뽑아 낼 수 있다.


최종본

내가 최종적으로 원한 것은 월, 주차 별로 통계를 뽑아내는 것이었다. 그래서 concat한 뒤에 group by를 해서 뽑아냈다. 

select  concat(month(구하고자 하는 날짜), '월 ', weekofyear(구하고자 하는 날짜) - weekofyear(해당 달의 첫째날) +1, '주차' ) as monthWeek from 테이블 

group by monthWeek;


후일담

뭐 일단은 만들어두긴 했는데, 나중에 보고나니 '통계를 내는 부분' 은 좋은 쿼리가 아니다. 그 이유는 인덱스를 타지도 않고 concat해놓은 스트링으로 새로운 컬럼을 만들어서 group by를 시켰으니 뭐 explain 떠보지 않더라도 완전 안좋을 거라는 예감이 폴폴폴폴폴폴 난다... 나중에 눈치봐서 저 쿼리를 개선하도록 해봐야겠다. 몰래.. 몰래.. ^_^ ;; 

'개발개발 > mySql' 카테고리의 다른 글

insert와 bulk insert 무엇을 써야할까요?  (1) 2018.10.04
DB를 쿼리로 업데이트 할때  (0) 2018.09.16
left join 시 속도 문제  (0) 2016.12.20
SELECT 정렬하기 정리  (0) 2016.12.13
order by varchar to int  (0) 2016.11.24

다 null이면... 좀 속도가 느리다...

'개발개발 > mySql' 카테고리의 다른 글

DB를 쿼리로 업데이트 할때  (0) 2018.09.16
mysql 월/주차 구하기  (0) 2018.01.06
SELECT 정렬하기 정리  (0) 2016.12.13
order by varchar to int  (0) 2016.11.24
week(date)에서 한주의 시작일 바꾸기  (0) 2016.11.24

1. 오름차순 정렬하기

  • select (칼럼) from (테이블) order by (정렬할 칼럼) asc
  • select (칼럼) from (테이블) order by (정렬할 칼럼) 

2. 내림차순 정렬하기

  • select (칼럼) from (테이블) order by (정렬할 칼럼) desc

3. 문자형 숫자 정렬하기

  • 문자형 * 1
    • select (칼럼) from table order by (문자형 숫자 * 1)  
  • 형변환
    • select (칼럼) from (테이블) order by (정렬할 칼럼) 

4. 랜덤으로 가지고오기

  • select (칼럼) from (테이블) order by rand() 
  • select (칼럼) from (테이블) order by rand() limit 3

5. 내맘대로 순서 정의해서 가지고 오기

  • SELECT (칼럼) from (테이블) order by field (칼럼, '3', '22', '1')

이렇게 하면  A열에서 3, 22, 1을 가지고 있는 row순으로 출력된다. 

'개발개발 > mySql' 카테고리의 다른 글

DB를 쿼리로 업데이트 할때  (0) 2018.09.16
mysql 월/주차 구하기  (0) 2018.01.06
left join 시 속도 문제  (0) 2016.12.20
order by varchar to int  (0) 2016.11.24
week(date)에서 한주의 시작일 바꾸기  (0) 2016.11.24

SELECT *
FROM mytable
ORDER BY ABS(mycol)

http://stackoverflow.com/questions/1625166/mysql-order-varchar-field-as-integer

'개발개발 > mySql' 카테고리의 다른 글

DB를 쿼리로 업데이트 할때  (0) 2018.09.16
mysql 월/주차 구하기  (0) 2018.01.06
left join 시 속도 문제  (0) 2016.12.20
SELECT 정렬하기 정리  (0) 2016.12.13
week(date)에서 한주의 시작일 바꾸기  (0) 2016.11.24

mysql에서 week(date)

WEEK(date[,mode])

This function returns the week number for date. The two-argument form of WEEK() enables you to specify whether the week starts on Sunday or Monday and whether the return value should be in the range from 0 to 53 or from 1 to 53. If the mode argument is omitted, the value of the default_week_format system variable is used. See Section 5.1.5, “Server System Variables”.

The following table describes how the mode argument works.

ModeFirst day of weekRangeWeek 1 is the first week …
0Sunday0-53with a Sunday in this year
1Monday0-53with 4 or more days this year
2Sunday1-53with a Sunday in this year
3Monday1-53with 4 or more days this year
4Sunday0-53with 4 or more days this year
5Monday0-53with a Monday in this year
6Sunday1-53with 4 or more days this year
7Monday1-53with a Monday in this year

For mode values with a meaning of with 4 or more days this year, weeks are numbered according to ISO 8601:1988:

  • If the week containing January 1 has 4 or more days in the new year, it is week 1.

  • Otherwise, it is the last week of the previous year, and the next week is week 1.


(출처: http://dev.mysql.com/doc/refman/5.5/en/date-and-time-functions.html#function_week)


그런데 내가 요청받은 것.

토요일부터 금요일까지를 한주로 계산해서 뽑아주세요...

힝....


'개발개발 > mySql' 카테고리의 다른 글

DB를 쿼리로 업데이트 할때  (0) 2018.09.16
mysql 월/주차 구하기  (0) 2018.01.06
left join 시 속도 문제  (0) 2016.12.20
SELECT 정렬하기 정리  (0) 2016.12.13
order by varchar to int  (0) 2016.11.24

+ Recent posts