운영체제(OS)에서 제공되는 기본적인 기능들을 제공.

 

os.getcwd(), os.chdir(path)

 

chdir() 함수는 현재 작업 디렉터리 위치를 변경하며,

getcwd()함수는 현재 작업 디렉터리의 위치를 가져올 때 쓰입니다.

>>> getcwd()

'C:\\Python3'

>>> chdir('Tools')

>>> getcwd()

'C:\\Python3\\Tools'

 

os.access(path, mode)

 

입력받은 <path>에 대해서 <mode>에 해당하는 작업이 가능한지의 여부를 반환합니다.

 

모드(mode)

설명

F_OK

해당 path의 존재 여부를 확인

R_OK

해당 path의 읽기 가능여부 확인

W_OK

해당 path의 쓰기 가능여부 확인

X_OK

해당 path의 실행 가능여부 확인

 

>>> access('.', F_OK)    # existence

True

>>> access('.', W_OK | X_OK | R_OK) # write, exec, read

True

 

os.listdir(path)

 

해당 경로(path)에 존재하는 파일과 디렉터리들의 리스트를 반환합니다.

>>> listdir('.')

['DLLs', 'Doc', 'include', 'Lib', 'libs', 'LICENSE.txt', 'NEWS.txt', 'python.exe', 'pythonw.exe',

'README.txt', 'tcl', 'Tools', 'w9xpopen.exe']

 

os.mkdir(path[, mode])

 

<path>에 해당하는 디렉터리를 생성합니다.

>>> mkdir('test1')

['DLLs', 'Doc', 'include', 'Lib', 'libs', 'LICENSE.txt', 'NEWS.txt', 'python.exe', 'pythonw.exe',

'README.txt', 'tcl', 'test1', 'Tools', 'w9xpopen.exe']

 

os.makedirs(path[, mode])

 

인자로 전달된 디렉터리를 재귀적으로 생성합니다.

이미 디렉터리가 생성되어 있는 경우나 권한이 없어 생성할 수 없는 경우는 예외를 발생합니다.

>>> makedirs('test2/sub1/sub2/leaf')

>>> listdir('test2/sub1/sub2')

['leaf']

>>> makedirs('test2/sub1/sub2/leaf') # 이미 존재하는 디렉터리를 생성하는 경우 예외 발생

Traceback (most recent call last):

File "<pyshell#18>", line 1, in <module>

makedirs('test2/sub1/sub2/leaf')

File "C:\Dev\Python3\lib\os.py", line 152, in makedirs

mkdir(name, mode)

WindowsError: [Error 183] 파일이 이미 있으므로 만들 수 없습니다: 'test2/sub1/sub2/sub3'

 

os.remove(path), os.unlink(path)

 

파일을 삭제 합니다.

>>> remove('test.txt')

>>> unilnk('test.txt')

 

os.rmdir(path)

 

디렉터리를 삭제합니다. 단, 디렉터리는 비어있어야만 합니다.

>>> mkdir('test1')

 

os.removedirs(path)

 

디렉터리를 연달아 삭제합니다.

 

 만약 '윈도우 탐색기'와 같은 애플리케이션으로 'sub1' 디렉터리를 보고 있다면,

removedirs() 함수로 'sub1' 디렉터리를 삭제할 수 없습니다. 탐색기를 종료하고 수행해야 합니다.

# leaf 디렉토리 삭제에 성공하면 차례로 sub2, sub1, test2의 순서로 삭제

>>> removedirs('test2/sub1/sub2/leaf')

 

os.rename(src, dst)

 

src를 dst로 이름을 변경하거나 이동합니다. 파일이나 디렉터리에 대해서 모두 적용 됩니다.

>>> rename('text.txt', 'renamed.txt')

 

os.renames(src, dst)

 

src를 dst로 이름을 변경하거나 이동합니다. rename과 다른점은 이동 시에 필요한 디렉터리들을

자동으로 생성한다는 것입니다.

>>> renames('renamed.txt', 'test_renames/moved.txt')

>>> listdir('test_renames')

['moved.txt']

 

os.stat(path)

 

경로에 해당하는 정보를 얻어옵니다.

아래의 예제와 같이 순차적으로 protection, inode, device, link, user id, group id, size,

last access time, last modified time, last change time 등을 나타냅니다.

(stat() 함수 결과 중 일부는 유닉스/리눅스 시스템에만 해당되는 것도 있습니다)

>>> stat('python.exe')

nt.stat_result(st_mode=33279, st_ino=281474976762468, st_dev=0, st_nlink=1, st_uid=0,

st_gid=0, st_size=26624, st_atime=1321851747, st_mtime=1315097496, st_ctime=1315097496)

 

os.utime(path, times)

 

경로에 해당하는 파일에 대해 액세스 시간(access time)과 수정 시간(modified time)을 <times>로

수정합니다. <times>가 None일 경우는 현재 시간으로 수정합니다. (유닉스의 touch 명령어와 유사)

>>> stat('readme.txt')

nt.stat_result(st_mode=33206, st_ino=281474976762465, st_dev=0, st_nlink=1, st_uid=0,

st_gid=0, st_size=6788, st_atime=1321797957, st_mtime=1315094610, st_ctime=1315094610)

>>> utime('readme.txt', None)

>>> stat('readme.txt')

nt.stat_result(st_mode=33206, st_ino=281474976762465, st_dev=0, st_nlink=1, st_uid=0,

st_gid=0, st_size=6788, st_atime=1321950244, st_mtime=1321950244, st_ctime=1315094610)

 

os.walk(top[, topdown=True[, onerror=None[, followlinks=False]]])

 

top으로 지정된 디렉터리를 순회하며 경로, 디렉터리명을 순차적으로 반환합니다.

다음의 구조로 test_walk, a, b 디렉터리를 만들어 놓고 walk를 실행

 

>>> for path,dirs,files in walk('test_walk'):

    print(path, dirs, files)

    

test_walk ['a', 'b'] []

test_walk\a [] []

test_walk\b [] ['readme.txt']

 

# topdown이 False로 설정된 경우에는 다음과 같이 디렉터리의 끝에서부터 위로 탐색

>>> for path,dirs,files in walk('test_walk', topdown=False):

    print(path, dirs, files)

    

test_walk\a [] []

test_walk\b [] ['readme.txt']

test_walk ['a', 'b'] []

 

os.umask(mask)

 

umask를 설정합니다. 수행하면 이전 mask 값이 반환됩니다. umask가 수행되면

이후 오픈 되는 파일이나 디렉터리에 (mode & ~umask)와 같이 적용됩니다.

 

os.pipe()

 

파이프를 생성합니다. 함수를 실행하면 읽기, 쓰기 전용 파이프의 파일 디스크립터가 반환됩니다.

 

(※ 파이프(pipe)란 프로세스 간 통신을 위한 공유 영역입니다. 여러 프로세스 간에 정보를 주고 받기

위해 만들어지는 공간이며, 하나의 프로세스가 정보를 쓰면 다른 프로세스에서 읽을 수 있습니다)

>>> pipe()

(3, 4)

 

os.fdopen(fd[, mode[, bufsize]])

 

파일 디스크립터를 이용해 파일 객체를 생성합니다.

 

(※ fdopen은 'from os import *'로 import가 안됩니다.

fdopen의 경우 'from os import fdopen'으로 따로 import 해주어야 합니다)

>>> from os import *

>>> from os import fdopen

 

>>> r,w = pipe()

>>> rd = fdopen(r)

>>> rd

<_io.TextIOWrapper name=3 mode='r' encoding='cp949'>

 

os.popen(command[, mode[, bufsize]])

 

인자로 전달된 command를 수행하며 파이프를 엽니다.

(파이썬3 에서는 Popen 클래스의 사용을 권장하지만 그대로 사용할 수도 있습니다)

 

(※ popen은 'from os import *'로 import가 안됩니다. popen의 경우 'from os import popen'으로

import하거나 import os 후 os.popen으로 사용해야 합니다)

>>> from os import popen

 

>>> p = popen('dir', 'r')

>>> p.read()

...<중략>...

2011-09-04 오전 09:51 26,624 python.exe\n

2011-09-04 오전 09:51 27,136 pythonw.exe\n

2011-11-22 오후 05:24 6,788 README.txt\n

2011-11-20 오후 11:06 <DIR> tcl\n

2011-11-20 오후 11:05 <DIR> Tools\n

2011-09-04 오전 09:51 49,664 w9xpopen.exe\n

6개 파일 396,879 바이트\n

9개 디렉터리 72,007,368,704 바이트 남음\n'

 

os.name

 

파이썬이 실행되는 운영체제의 이름을 나타냅니다. (ex: 'nt', 'posix', 'mac'등...)

>>> name

'nt'

 

os.environ

 

환경변수들을 나타내는 사전입니다.

>>> environ

environ({'TMP': 'C:\\DOCUME~1\\ADMINI~1\\LOCALS~1\\Temp',

'COMPUTERNAME': 'WIN2003', 'USERDOMAIN': 'WIN2003',

'COMMONPROGRAMFILES': 'C:\\Program Files\\Common Files', ...<중략>...})

>>> environ['OS']

'Windows_NT'

>>> environ['userprofile']

'C:\\Documents and Settings\\Administrator'

 

os.getpid()

 

현재 프로세스 아이디를 반환합니다.

>>> getpid()

3380

 

os.getenv(varname[, value])

 

환경 변수의 값을 얻어 옵니다. 다만 해당 환경 변수가 없을 경우에는 인자로 전달된 <value>값을

반환합니다. value가 생략되고 해당 환경 변수가 없으면 None을 반환 합니다.

>>> getenv('homepath')

'\\Documents and Settings\\Administrator'

>>> getenv('test', '')

''

 

os.putenv(varname, value)

 

환경변수 <varname>을 <value>로 설정합니다. 자식 프로세스에게 영향을 미칩니다.

>>> putenv('test', '\\tmp\\test')

 

# 자식 프로세스에게 영향을 미치므로, putenv()의 결과 확인.

>>> from os import popen

>>> p = popen('''python -c "import os; print(os.getenv('test'))"''''r')

>>> p.read()

'\\tmp\\test\n'

 

os.strerror(code)

 

에러 코드에 해당하는 에러 메시지를 보여줍니다.

>>> for i in range(0, 44):

print (i, strerror(i))

 

0 No error

1 Operation not permitted

2 No such file or directory

3 No such process

4 Interrupted function call

5 Input/output error

6 No such device or address

7 Arg list too long

8 Exec format error

9 Bad file descriptor

10 No child processes

...<중략>...

 

os.system(command)

 

<command>를 실행하며, 성공한 경우 0을 반환합니다.

[계산기 실행화면]

 

os.startfile(path[, operation])

 

<path>를 os에서 지정된 프로그램으로 실행합니다.

또한 <operation>으로 명시적으로 수행할 프로그램을 지정할 수 있습니다.

 

(※ starfile('LICENSE.txt')의 경우 system("Notepad LICENSE.txt')와 유사하지만 system()을 사용하는

경우에는 파이썬 프로그램의 실행이 잠시 멈추고 system()이 끝나길 기다리게 되고, startfile()은

멈추지 않고 계속 실행됩니다.)

 

os.execl(path, arg0, arg1, ...)

os.execle(path, arg0, arg1, ..., env)

os.execlp(file, arg0, arg1, ...)

os.execlpe(file, arg0, arg1, ..., env)

os.execv(path, args)

os.execve(path, args, env)

os.execvp(file, args)

os.execvpe(file, args, env)

 

위의 함수는 현재 프로세스에서 새로운 프로그램을 수행시키며 리턴은 하지 않습니다.

인자에 따라 여러 가지 exec로 나뉘어지는데, 우선'l'이 붙은 것들은 입력인자들의 수가 정해져

있는 경우이고, 'v'가 붙은 것들은 args라는 튜플로 입력인자를 받습니다. 'e'가 붙은 경우는

환경변수 env를 받느냔 아니냐의 차이이며, 'p'는 환경변수의 path를 이용하는 경우입니다.

>>> execl('C:\\Python3\python''python''-v')

>>> execv('python'('python', '-v'))

>>> execle('C:\Python3\python''python', '-v', {"HOME":"C:\\"})


반응형

완전 퍼온 글이다. 도움이 될 듯 싶어서 공유한다.



BINLOG FORMAT은 세가지가 있다. 

1) STATEMENT
2) MIXED
3) ROW 

이 중 MIXED는 1),3) 의 혼합 형태로 binary 로그를 남기게 되는데 
몇몇 일관성을 보장하지 못하는 케이스를 제외하고는 1) STATEMENT 형태로 남게 된다. 

그런데 ISOLATION LEVEL 도 binary 로그 포맷에 영향을 주게 되는데 
ISOLATION LEVEL 이 READ-COMMITTED의 경우 binlog_format을 MIXED 이상으로 설정을 해야 한다. 


ISOLATION LEVEL 

1) READ-COMMITTED 

The default isolation level for most database systems ( nut not MySQL ) is READ COMMITTED. It satisfies the simple
definition of isolation used earlier: a transaction will see only those changes made  by transactions that were already committed when it began, and its changes won't be visible to others until it has committed. This level still allows what's 
known as a nonrepeatable read. This means you can run the same statement twice and see different data.

2) REPEATABLE READ

It guarantees that any rows a transaction reads will "look the same" in subsequent reads within the same transaction, but 
in theory it still allows another tricky problem: phantom reads. Simply put, a phantom read can happen when you select some range of rows, another transaction inserts a new row into the range, and then you select the same range again: 
you will then see the new "phantom" row. InnoDB and XtraDB solve the phantom read problem with multiversion comcurrency control, which we explain later in this chapter. REPEATABLE READ is MySQL's default transaction isolation level.


Isolation level을 read committed로 하고 binlog format을 MIXED로 한 후 대부분의 binary 로그가 statement 형태로 남을 것으로 생각했다. 그런데 전부다 row format 으로 남았고, 이것이 정상이라고 한다. isolation level이 repeatable read 에서는 binlog format MIXED 일 때 대부분의 경우 statement 형태로 남고 일관성이 보장이 안되는 특정 경우에만 row 형태로 남았다. 

이건 isolation level의 개념만 다시 확인해 보면 당연한 결과이다. 

테스트를 해보자. 

1. transaction_isolation = repeatable-read


두 개의 세션에서 트랜잭션을 열고 아래 번호 순서대로 DML이 실행한다. 그리고 
 

 

[root@localhost] (test) 12:12> rollback;
Query OK, 0 rows affected (0.00 sec)


####### Session A

[root@localhost] (test) 12:13> start transaction ;
Query OK, 0 rows affected (0.00 sec)

[root@localhost] (test) 12:14>
[root@localhost] (test) 12:14> update trans_test2 set b=999 where a=1;   ----------- 1)
Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0

[root@localhost] (test) 12:14> update trans_test2 set b=222 where a=10;  ----------- 3) 
Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0

[root@localhost] (test) 12:14> commit;
Query OK, 0 rows affected (0.00 sec)

 

 

####### Session B

[root@localhost] (test) 12:13> start transaction ;
Query OK, 0 rows affected (0.00 sec)

[root@localhost] (test) 12:14>
[root@localhost] (test) 12:14> update trans_test2 set b=999 where a=20;  ------------ 2)
Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0

[root@localhost] (test) 12:14> update trans_test2 set b=222 where a=25;  ------------ 4)
Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0

[root@localhost] (test) 12:14> commit;
Query OK, 0 rows affected (0.00 sec)

 

####### binary log를 확인해 보면 먼저 commit 된 transaction 순서대로 기록된다. ( DML 실행 순서 아님 )


#131001 12:14:08 server id 12  end_log_pos 10509        Query   thread_id=2     exec_time=0     error_code=0
use `test`/*!*/;
SET TIMESTAMP=1380597248/*!*/;
update trans_test2 set b=999 where a=1f<9c>ⓒK
/*!*/;
# at 10509
#131001 12:14:21 server id 12  end_log_pos 10622        Query   thread_id=2     exec_time=0     error_code=0
SET TIMESTAMP=1380597261/*!*/;
update trans_test2 set b=222 where a=10oI^PØ
/*!*/;
# at 10622
#131001 12:14:47 server id 12  end_log_pos 10653        Xid = 127
COMMIT/*!*/;
# at 10653
#131001 12:14:13 server id 12  end_log_pos 10732        Query   thread_id=3     exec_time=0     error_code=0
SET TIMESTAMP=1380597253/*!*/;
BEGINU<90>%²
/*!*/;
# at 10732
#131001 12:14:13 server id 12  end_log_pos 10845        Query   thread_id=3     exec_time=0     error_code=0
use `test`/*!*/;
SET TIMESTAMP=1380597253/*!*/;
update trans_test2 set b=999 where a=20AE§¥
/*!*/;
# at 10845
#131001 12:14:44 server id 12  end_log_pos 10958        Query   thread_id=3     exec_time=0     error_code=0
SET TIMESTAMP=1380597284/*!*/;
update trans_test2 set b=222 where a=25^]GRA
/*!*/;
# at 10958
#131001 12:14:50 server id 12  end_log_pos 10989        Xid = 129
COMMIT/*!*/;
DELIMITER ;
# End of log file
ROLLBACK /* added by mysqlbinlog */;
/*!50003 SET COMPLETION_TYPE=@OLD_COMPLETION_TYPE*/;

 


 

2. transaction_isolation = read-committed

 

=== session A

[root@localhost] (test) 13:27> start transaction;
Query OK, 0 rows affected (0.00 sec)

[root@localhost] (test) 13:32>
[root@localhost] (test) 13:32> update trans_test2 set b=444 where a=1;    ---------- 1)
Query OK, 1 row affected (0.16 sec)
Rows matched: 1  Changed: 1  Warnings: 0

[root@localhost] (test) 13:32> select * from trans_test2 where a=20;      ---------- 2) 
+----+------+
| a  | b    |
+----+------+
| 20 |  999 |
+----+------+
1 row in set (0.01 sec)

[root@localhost] (test) 13:33> select * from trans_test2 where a=20;      ----------- 5) 3) DML 결과가 보인다.  
+----+------+
| a  | b    |
+----+------+
| 20 |  777 |
+----+------+
1 row in set (0.00 sec)

[root@localhost] (test) 13:33> update trans_test2 set b=787 where a=20 and b=777;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0

[root@localhost] (test) 13:33>
[root@localhost] (test) 13:33> commit;
Query OK, 0 rows affected (0.00 sec)

[root@localhost] (test) 13:33> select * from trans_test2 where a=20;
+----+------+
| a  | b    |
+----+------+
| 20 |  787 |
+----+------+
1 row in set (0.00 sec)

 

=== session B

[root@localhost] ((none)) 13:28> use test
Database changed
[root@localhost] (test) 13:28> start transaction;
Query OK, 0 rows affected (0.00 sec)

[root@localhost] (test) 13:33>
[root@localhost] (test) 13:33> update trans_test2 set b=777 where a=20;    ----------- 3) 
Query OK, 1 row affected (0.02 sec)
Rows matched: 1  Changed: 1  Warnings: 0

[root@localhost] (test) 13:33>
[root@localhost] (test) 13:33> commit;   -------- 4) 
Query OK, 0 rows affected (0.00 sec)

 

위 테스트 처럼 isolation level READ-COMMITTED의 경우  현재의 트랜잭션이 종료 되지 않은 상황에서 다른 트랜잭션이 commit 이 되면 그 트랜잭션 통해 변경된 값이 보이게 된다. 그런데 이런 경우를 statement 방식으로 트랜잭션 단위로 묶어서 순서대로 로깅해서 그 순서대로 쿼리를 실행하게 될 경우 실제 상황을 그대로 재현할 수 없게 되고 다른 결과가 나올 수 있게 된다. 그렇기 때문에 isolation level READ-COMMITTED , binlog_format MIXED 에서 는 binary log가 row 형태로 남게 된다. 

반응형

utf-8 과 utf8mb4 에 대해서 알아보자.


해당 캐릭터셋은 현재 회사 DB가 euckr 인데...이것을 utf8로 변경하고자 확인하던 도중 많은 도움이 된 블로그가 있어서 정리하면서 같이 소개해 본다.


아래 블로그의 모든 내용을 조금씩 정리하면서 작성하였습니다.

가져온 블로그 : https://blog.lael.be/post/917




utf-8 문자 집한은 1~4 byte까지 저장이 가능하게 설계(가변 바이트)


 -> 다국어가 지원이 되기 때문에 전세계 모든 언어를 저장이 가능하다

 -> MySQL에서 utf8 을 3 Byte 가변 자료형으로 설계


하지만 최근에 나온 4 byte 문자열(Emoji 같은 것)을 utf8 에 저장하면 값이 손실되는 현상이 발생

(charset 은 utf8 / collation 는 utf8_general_ci)


4 Byte UTF-8 문자열

 : MySQL에서 기존 설계대로 가변 4 Byte utf-8 문자열을 저장할 수 있는 자료형을 추가

 -> 이것이 utf8mb4 로 지정 (MySQL 5.5.3 에서부터 추가)


- utf8 : Basic Plane.


- utf8mb4 : Basic Plane + Supplementary Plane.


추가로 utf8mb4 는 Emoji 문자열 지원

 

- 스마트폰에서 지원하는 문자들을 지원 (SMP - Supplementary Multilingual Plane)

  (모바일 어플의 경우의 DB는 utf8mb4 로 설정하는 것이 좋을 듯 싶다) 

 아래 이미지 참고 





즉, utf8 (가변 3바이트) utf8mb4 (가변 4바이트) 저장공간의 크기




Collaction


Collaction은 텍스트 데이터를 정렬 (Order by) 할 때 사용

text 계열 자료형에서만 사용할 수 있는 속성


utf8_bin (utf8mb4_bin)


Binary 저장 값 그대로 정렬

Hex 코드 (16진수)로 되어 있기에 해당 값으로 정렬


utf8_uniconde_ci (utf8mb4_unicode_ci)


한국어, 영어, 중국어, 일본어 사용환경에서는 general_ci 와 unicode_ci 의 결과가 동일

하지만 외국어 및 특수문자가 들어가는 경우 다름




utf8mb4 charset 에, utf8mb4_unicode_ci collation 사용 하는 것이 좋을 듯 싶다.


문제점


1) 다국어를 처리할 수 있는 UTF-8 이라는 저장방식이 있음. 원래 설계는 가변4바이트임.


2) 전세계 모든 언어문자를 다 카운트 해봤는데 3 바이트가 안됨.


3) MYSQL/MariaDB 에서는 공간절약+속도향상 을 위해서 utf8 을 가변3바이트로 설계함.


4) Emoji 같은 새로나온 문자가 UTF-8의 남은 영역을 사용하려함 (4바이트 영역).


5) MYSQL/MariaDB 에서 가변4바이트 자료형인 utf8mb4 를 추가함.  (2010년 3월에).



반응형

매일 하나씩 공유하고 연구하자는게 하루만에 무너졌다....

다시 시작해보자!!!




mysqlbinlog 관련하여 테스트 중 binlog_format 을 row로 변경하여 테스트 하던 도중 아래와 같은 에러가 발생 하였다.


ERROR: Error in Log_event::read_log_event(): 'Found invalid event in binary log', data_len: 47, event_type: 19



으음.....여기저기 찾아봤는데 원하는 답변을 못 찾았다...

그러다 어느 중국 사이트에서 유사 관련하여 올려 놓은 것을 확인할 수 있었다.


단순 default 로 잡힌 mysqlbinlog 의 version을 확인해 보자



3.2 인것을 확인할 수 있다.

버전차이 때문에 발생할 수 있으니 다음과 같이 엔진에 있는 mysqlbinlog 로 확인해 보자




3.4 인 것을 확인할 수 있다.


그렇다면 다시 binlog가 제대로 되는지 확인해 보자



제대로 import되는 것을 확인할 수 있다.


row 관련한 내용은 좀 더 공부해야겠다...참고로 아래 이미지를 보면 정말 oracle 의 rowid 를 보는 듯한 느낌이 난다...



반응형
최근에 너무 바빴다..
아픈것도 있었고...심신의 위로가 너무나도 필요했다.

의욕도 생기지 않은것도 한몫 했다...

이런 하소연은 Life에 일기로 써야지....ㅋㅋ쓰다보면 위로가 될꺼라 믿고...


각설하고 오늘부터 하루에 기술 관련 정리하여 올리자고 한다.

작심 3일을 매주 2번..씩 다짐한다.




오늘 Binlog_format에 대한 정리한 것을 공유해 본다.


아래 블로그에서 참고 하였다.

[출처] : http://mysqldba.tistory.com/196



★ binlog_format 종류 및 차이

  • Statement Format : 가장 오래된 Format으로 데이터 변경에서 사용되는 모든 쿼리를 쿼리대로 저장하는 방식을 말함(5.7까지 기본 Format)
  • Row Format : 변경 작업으로 변경된 모든 Row의 정보를 기록하는 방식
  • Mixed Format : Statement 방식과 Row 방식을 혼합한 방식으로 기본은 Statement 방식이고, 몇몇의 경우에는 Row방식으로 동작하는 방식
mysql> set global binlog_format = 'STATEMENT';
mysql> set global binlog_format = 'ROW';
mysql> set global binlog_format = 'MIXED';

 - global 대신 session 으로 변경 가능

* Row 와 Statement 

데이터베이스에 작은 변경을 많이 발생 시키는 쓰레드는 열 기반 로깅을 선호한다. 
WHERE 구문에 있는 많은 열과 매치가 되는 업데이트를 실행하는 쓰레드는 명령문 기반 로깅을 선호하는데, 그 이유는 많은 열을 로깅하는 것 보다는 적은 명령문 로깅이 효과적이기 때문이다.

마스터에서 오랜 실행 시간 동안 실행되지만 비교적 적은 수의 열만을 수정하는 명령문들이 있다. 
이러한 명령문들은 열 기반 로깅을 사용해서 복제하는 것이 보다 효과적이다.


* Defualt 


* STATEMENT 일때 로그 흔적


* row 형태의 format




* Format 변경 시 문제 발생하는 시점
    • Trigger나 Stored Function을 사용하고 있는 경우
    • NDB Cluster Storage Engine을 사용하고 있는 경우
    • 현재 Temporary Table을 사용하고 있는 세션이 있는 경우

  • Mixed Binary Logging Format 을 사용하면 Binary log를 작성하면 MySQL은 자동적으로 Statement방식과 Row 방식을 섞어서 기술
    • Row 방식으로 작성 되는 경우
      • NDB Cluster Table에 DML이 실행된 경우
      • UUID()를 사용한 경우
      • Auto_Increment 칼럼을 가지고 있는 테이블에 연결된 Trigger나 Stored Function이 생성되어 사용되는 경우
      • Insert Delayed가 실행하는 경우
      • User Defined Function 을 호출할 때 등
  • Storage Engine 별로 지원하는 format

Storage Engine

Row Logging Supported

Statement Logging Supported

Archive

Yes

Yes

Blackhole

Yes

Yes

CSV

Yes

Yes

Example

Yes

No

Federated

Yes

Yes

Heap

Yes

Yes

InnoDB

Yes

Yes / When the Transaction isolation level is Repeatable Read or Serializable : No otherwise.

MyISAM

Yes

Yes

Merge

Yes

Yes

NDB

Yes

No


  • Storage Engine별 지원하는 logging 형태에 따라 2가지로 분류
    1. SLC (Statement-Logging Capable) - Statement Logging 방식을 지원하는 Storage Engine.
    2. RLC (Row-Logging Capable) - Row Logging 방식을 지원하는 Storage Engine
  • Binary Log에 작성되는 3가지 종류
    1. Safe : Statement 방식으로 작성 시 Replication 이나 복구 시에 문제가 되지 않는 쿼리 형태
    2. UnSafe : Statement 방식으로 작성 시 Replication 이나 복구 시에 문제가 되는 쿼리 형태
    3. Row/Binary Injection : Row Event로 Row Based 방식으로 실행하기 위해 저장되는 Event형태 (Row format 으로 로깅해야 지만, 변경 내역이 저장되는 것을 의미)
  •  MySQL은 Grant 작업은 직접적인 DML로 진행될 수도 있으나 간접적인 DDL 구문으로 실행 가능
    1. 직접적으로 실행되는 DML 는 Binlog_format에 따라 작성되는 방법이 다름 (Insert / Update / Delete / Replace / Do / Load Data Infile / Select / Truncate table)
    2. 간접적으로 실행되는 DDL 문은 Binlog_format과 상관없이 무조건 Statement방식으로 저장(Grant / Revoke / Set Password / Rename User / Create / Alter Drop)
    3. Create table .. Select 경우 Create Table 은 Statement 방식으로 저장되고 Select 부분은 Binlog_format 설정값에 따라 달라짐


반응형
Redis 관련해서 기초 이해하기 위해 아래 블로그도 많은 도움이 되었다.
물론 해당 내용이 2012년도? 내용이기에 변경된 부분도 조금 있다.

아래 내용의 경우 현재 Cluster 가 개발되어 있다.

현재 버전 2.4.15에서는 Clustering을 지원하지 않아서 Sharding을 사용할 수 밖에 없지만 2012년 내에 Clustering기능이 포함된다고 하니, 확장성에 대해서 기대해볼만하다. redis가 지원할 clustering 아키텍쳐는 ( http://redis.io/presentation/Redis_Cluster.pdf ) 를 참고하기 바란다.

Redis Cluster

Link : http://www.redisgate.com/redis/cluster/cluster.php


조만간에 Redis 설치 테스트 하여 업로드할 계획이다.

여러가지를 이것저것 해보는 것이 좋을 수도 있지만...너무 조급심을 내고 있지 않는가 걱정도 된다.




출처 : http://bcho.tistory.com/654


redis Introduction


Intro
Redis는 "REmote DIctionary System"의 약자로 메모리 기반의 Key/Value Store 이다.
Cassandra나 HBase와 같이 NoSQL DBMS로 분류되기도 하고, memcached와 같은 In memory 솔루션으로 분리되기도 한다.
성능은 memcached에 버금가면서 다양한 데이타 구조체를 지원함으로써 Message Queue, Shared memory, Remote Dictionary 용도로도 사용될 수 있으며, 이런 이유로 인스탄트그램, 네이버 재팬의 LINE 메신져 서비스, StackOverflow,Blizzard,digg 등 여러 소셜 서비스에 널리 사용되고 있다.
BSD 라이센스 기반의 오픈 소스이며 최근 VMWare에 인수되어 계속해서 업그레이드가 되고 있다.
16,000 라인정도의 C 코드로 작성되었으며, 클라이언트 SDK로는
Action Script,C,C#,C++,Clojure,Erlang,Java,Node.js,Objective-C,Perl,PHP,Python,Smalltalk,Tcl등 대부분의 언어를 지원한다. (참고 : http://www.redis.io/clients )

이번 글에서는 Redis란 무엇인지, 그리고 대략적인 내부 구조에 대해서 살펴보도록 한다.

1. Key/Value Store
Redis는 기본적으로 Key/Value Store이다. 특정 키 값에 값을 저장하는 구조로 되어 있고 기본적인 PUT/GET Operation을 지원한다.

단, 이 모든 데이타는 메모리에 저장되고, 이로 인하여 매우 빠른 write/read 속도를 보장한다. 그래서 전체 저장 가능한 데이타 용량은 물리적인 메모리 크기를 넘어설 수 있다. (물론 OS의 disk swapping 영역등을 사용하여 확장은 가능하겠지만 성능이 급격하게 떨어지기 때문에 의미가 없다.)
데이타 억세스는 메모리에서 일어나지만 server restart 와 같이 서버가 내려갔다가 올라오는 상황에 데이타를 저장을 보장하기 위해서 Disk를 persistence store로 사용한다.

2. 다양한 데이타 타입
단순한 메모리 기반의 Key/Value Store라면 이미 memcached가 있지 않은가? 그렇다면 어떤 차이가 있길래 redis가 유행하는 것일까?
redis가 Key/Value Store이기는 하지만 저장되는 Value가 단순한 Object가 아니라 자료구조를 갖기 때문에 큰 차이를 보인다.
redis가 지원하는 데이타 형은 크게 아래와 같이 5가지가 있다.

1) String
일반적인 문자열로 최대 512mbyte 길이 까지 지원한다.
Text 문자열 뿐만 아니라 Integer와 같은 숫자나 JPEG같은 Binary File까지 저장할 수 있다.

2) Set
set은 string의 집합이다. 여러개의 값을 하나의 Value 내에 넣을 수 있다고 생각하면 되며 블로그 포스트의 태깅(Tag)등에 사용될 수 있다.
재미있는 점은 set간의 연산을 지원하는데, 집합인 만큼 교집합, 합집합, 차이(Differences)를 매우 빠른 시간내에 추출할 수 있다.

3) Sorted Set
set 에 "score" 라는 필드가 추가된 데이타 형으로 score는 일종의 "가중치" 정도로 생각하면 된다.
sorted set에서 데이타는 오름 차순으로 내부 정렬되며, 정렬이 되어 있는 만큼 score 값 범위에 따른 쿼리(range query), top rank에 따른 query 등이 가능하다.


4) Hashes
hash는 value내에 field/string value 쌍으로 이루어진 테이블을 저장하는 데이타 구조체이다.
RDBMS에서 PK 1개와 string 필드 하나로 이루어진 테이블이라고 이해하면 된다.


5) List
list는 string들의 집합으로 저장되는 데이타 형태는 set과 유사하지만, 일종의 양방향 Linked List라고 생각하면 된다. List 앞과 뒤에서 PUSH/POP 연산을 이용해서 데이타를 넣거나 뺄 수 있고, 지정된 INDEX 값을 이용하여 지정된 위치에 데이타를 넣거나 뺄 수 있다. 


6) 데이타 구조체 정리
지금까지 간략하게 redis가 지원하는 데이타 구조체들에 대해서 살펴보았다.
redis의 데이타 구조체의 특징을 다시 요약하자면
  • Value가 일반적인 string 뿐만 아니라, set,list,hash와 같은 집합형 데이타 구조를 지원한다.
  • 저장된 데이타에 대한 연산이나 추가 작업 가능하다. (합집합,교집합,RANGE QUERY 등)
  • set은 일종의 집합, sorted set은 오름차순으로 정렬된 집합, hash는 키 기반의 테이블, list는 일종의 링크드 리스트 와 같은 특성을 지니고 있다.
이러한 집합형 데이타 구조 (set,list,hash)등은 redis에서 하나의 키당 총 2^32개의 데이타를 이론적으로 저장할 수 있으나, 최적의 성능을 낼 수 있는 것은 일반적으로 1,000~5,000개 사이로 알려져 있다.

데이타 구조에 따른 저장 구조를 정리해서 하나의 그림에 도식화해보면 다음과 같다.



3. Persistence
앞서도 언급하였듯이, redis는 데이타를 disk에 저장할 수 있다. memcached의 경우 메모리에만 데이타를 저장하기 때문에 서버가 shutdown 된후에 데이타가 유실 되지만, redis는 서버가 shutdown된 후 restart되더라도, disk에 저장해놓은 데이타를 다시 읽어서 메모리에 Loading하기 때문에 데이타 유실되지 않는다.
redis에서는 데이타를 저장하는 방법이 snapshotting 방식과 AOF (Append on file) 두가지가 있다.

1) snapshotting (RDB) 방식
순간적으로 메모리에 있는 내용을 DISK에 전체를 옮겨 담는 방식이다.
SAVE와 BGSAVE 두가지 방식이 있는데,
SAVE는 blocking 방식으로 순간적으로 redis의 모든 동작을 정지시키고, 그때의 snapshot을 disk에 저장한다.
BGSAVE는 non-blocking 방식으로 별도의 process를 띄운후, 명령어 수행 당시의 메모리 snaopshot을 disk에 저장하며, 저장 순간에 redis는 동작을 멈추지 않고 정상적으로 동작한다.
  • 장점 : 메모리의 snapshot을 그대로 뜬 것이기 때문에, 서버 restart시 snapshot만 load하면 되므로 restart 시간이 빠르다.
  • 단점 : snapshot을 추출하는데 시간이 오래 걸리며, snapshot 추출된후 서버가 down되면 snapshot 추출 이후 데이타는 유실된다.
    (백업 시점의 데이타만 유지된다는 이야기)
2) AOF 방식
AOF(Append On File) 방식은 redis의 모든 write/update 연산 자체를 모두 log 파일에 기록하는 형태이다. 서버가 재 시작될때 기록된  write/update operation을 순차적으로 재 실행하여 데이타를 복구한다. operation 이 발생할때 마다 매번 기록하기 때문에, RDB 방식과는 달리 특정 시점이 아니라 항상 현재 시점까지의 로그를 기록할 수 있으며, 기본적으로 non-blocking call이다.
  • 장점 : Log file에 대해서 append만 하기 때문에, log write 속도가 빠르며, 어느 시점에 server가 down되더라도 데이타 유실이 발생하지 않는다.
  • 단점 : 모든 write/update operation에 대해서 log를 남기기 때문에 로그 데이타 양이 RDB 방식에 비해서 과대하게 크며, 복구시 저장된 write/update operation을 다시 replay 하기 때문에 restart속도가 느리다.
3) 권장 사항
RDB와 AOF 방식의 장단점을 상쇠하기 위해서 두가지 방식을 혼용해서 사용하는 것이 바람직한데
주기적으로 snapshot으로 백업하고, 다음 snapshot까지의 저장을 AOF 방식으로 수행한다.
이렇게 하면 서버가 restart될 때 백업된 snapshot을 reload하고, 소량의 AOF 로그만 replay하면 되기 때문에, restart 시간을 절약하고 데이타의 유실을 방지할 수 있다.


4. Pub/Sub Model
redis는 JMS나 IBM MQ 같은 메세징에 활용할 수 있는데, 1:1 형태의 Queue 뿐만 아니라 1:N 형태의 Publish/Subscribe 메세징도 지원한다.(Publish/Subscribe 구조에서 사용되는 Queue를 일반적으로 Topic이라고 한다.)
하나의 Client가 메세지를 Publish하면, 이 Topic에 연결되어 있는 다수의 클라이언트가 메세지를 받을 수 있는 구조이다. (※ Publish/Subscribe 형태의 messaging 에 대해서는 http://en.wikipedia.org/wiki/Pub/sub  를 참고하기 바란다.)


재미있는 것중에 하나는 일반적인 Pub/Sub 시스템의 경우 Subscribe 하는 하나의 Topic에서만 Subscribe하는데 반해서, redis에서는 pattern matching을 통해서 다수의 Topic에서 message 를 subscribe할 수 있다.
예를 들어 topic 이름이 music.pop music,classic 이라는 두개의 Topic이 있을때, "PSUBSCRIBE music.*"라고 하면 두개의 Topic에서 동시에 message를 subscribe할 수 있다.

5. Replication Topology
redis는 NoSQL 계열의 Key/Store Storage인데 반해서 횡적 확장성을 지원하지 않는다.
쉽게 말해서 2.4.15 현재 버전 기준으로는 클러스터링 기능이 없다. (향후 지원 예정)
그래서 확장성(scalability)과 성능에 제약사항이 있는데, 다행이도 Master/Slave 구조의 Replication(복제)를 지원하기 때문에 성능 부분에 있어서는 어느정도 커버가 가능하다.

Master/Slave replication
Master/Slave Replication이란, redis의 master node에 write된 내용을 복제를 통해서 slave node에 복제 하는 것을 정의한다.
1개의 master node는 n개의 slave node를 가질 수 있으며, 각 slave node도 그에 대한 slave node를 또 가질 수 있다.


이 master/slave 간의 복제는 Non-blocking 상태로 이루어진다. 즉 master node에서 write나 query 연산을 하고 있을 때도 background로 slave node에 데이타를 복사하고 있다는 이야기고, 이는 master/slave node간의 데이타 불일치성을 유발할 수 있다는 이야기이기도 하다.
master node에 write한 데이타가 slave node에 복제중이라면 slave node에서 데이타를 조회할 경우 이전의 데이타가 조회될 수 있다.

Query Off Loading을 통한 성능 향상
그러면 이 master/slave replication을 통해서 무엇을 할 수 있냐? 성능을 높일 수 있다. 동시접속자수나 처리 속도를 늘릴 수 있다. (데이타 저장 용량은 늘릴 수 없다.) 이를 위해서 Query Off Loading이라는 기법을 사용하는데
Query Off Loading은 master node는 write only, slave node는 read only 로 사용하는 방법이다.
단지 redis에서만 사용하는 기법이 아니라, Oracle,MySQL과 같은 RDBMS에서도 많이 사용하는 아키텍쳐 패턴이다.
대부분의 DB 트렌젝션은 웹시스템의 경우 write가 10~20%, read가 70~90% 선이기 때문에, read 트렌젝션을 분산 시킨다면, 처리 시간과 속도를 비약적으로 증가 시킬 수 있다. 특히 redis의 경우 value에 대한 여러가지 연산(합집합,교집합,Range Query)등을 수행하기 때문에, 단순 PUT/GET만 하는 NoSQL이나 memcached에 비해서 read에 사용되는 resource의 양이 상대적으로 높기 때문에 redis의 성능을 높이기 위해서 효과적인 방법이다.

Sharding 을 통한 용량 확장
redis가 클러스터링을 통한 확장성을 제공하지 않는다면, 데이타의 용량이 늘어나면 어떤 방법으로 redis를 확장해야 할까?
일반적으로 Sharding이라는 아키텍쳐를 이용한다. Sharding은 Query Off loading과 마친가지로, redis 뿐만 아니라 일반적인 RDBMS나 다른 NoSQL에서도 많이 사용하는 아키텍쳐로 내용 자체는 간단하다.
여러개의 redis 서버를 구성한 후에, 데이타를 일정 구역별로 나눠서 저장하는 것이다. 예를 들어 숫자를 key로 하는 데이타가 있을때 아래와 그림과 같이 redis 서버별로 저장하는 key 대역폭을 정해놓은 후에, 나눠서 저장한다.
데이타 분산에 대한 통제권은 client가 가지며 client에서 애플리케이션 로직으로 처리한다.

현재 버전 2.4.15에서는 Clustering을 지원하지 않아서 Sharding을 사용할 수 밖에 없지만 2012년 내에 Clustering기능이 포함된다고 하니, 확장성에 대해서 기대해볼만하다. redis가 지원할 clustering 아키텍쳐는 ( http://redis.io/presentation/Redis_Cluster.pdf ) 를 참고하기 바란다.

6. Expriation
redis는 데이타에 대해서 생명주기를 정해서 일정 시간이 지나면 자동으로 삭제되게 할 수 있다.
redis가 expire된 데이타를 삭제 하는 정책은 내부적으로 Active와 Passive 두 가지 방법을 사용한다.
Active 방식은 Client가 expired된 데이타에 접근하려고 했을 때, 그때 체크해서 지우는 방법이 있고
Passive 방식은 주기적으로 key들을 random으로 100개만 (전부가 아니라) 스캔해서 지우는 방식이 이다.
expired time이 지난 후 클라이언트에 의해서 접근 되지 않은 데이타는 Active 방식으로 인해서 지워지지 않고 Passive 방식으로 지워져야 하는데, 이 경우 Passive 방식의 경우 전체 데이타를 scan하는 것이 아니기 때문에, redis에는 항상 expired 되었으나 지워지지 않는 garbage 데이타가 존재할 수 있는 원인이 된다.

7. Redis 설치(윈도우즈)
https://github.com/rgl/redis/downloads 에서 최신 버전 다운로드 받은후
redis-server.exe를 실행

클라이언트는 redis-cli.exe를 실행
아래는 테스트 스크립트
    % cd src
    % ./redis-cli
    redis> ping
    PONG
    redis> set foo bar
    OK
    redis> get foo
    "bar"
    redis> incr mycounter
    (integer) 1
    redis> incr mycounter
    (integer) 2
    redis> 


참고 자료


반응형

Redis 란?? slide


[펌]

http://www.slideshare.net/krisjeong/this-is-redis-kor-slideshare?next_slideshow=1



[출처] http://blog.daum.net/smufu/4

업무때문에 스터디 하다가 스터디 하다가 세미나도 하고


너무 괜찮아 보여서 현재 서비스중인 Product에 적용을 위해서


작업중인 NoSQL되시겠다...


각설하고, 그럼 먼저 NoSQL이란 무었인가?


Not only SQL의 약자 되시겠다..


혹자는 No SQL이라고 생각할지도 모르나.. 그런 기우일랑 접어두고..


SQL만이 아닌 다른 저장소 쯤으로 이해 하면 되겠다..


여기에(http://www.slideshare.net/krisjeong/redis-intro) 내가 작성한 세미나 자료 있으니 한번 훑어 보시면 이해 하는데 큰 도움이 되리라 생각된다.


Redis는 자주 Memcached와 비교되는 in memory 저장소 이다.


Memcached의 기본적인 특징.

1. 처리 속도가 빠르다.

   - 당연히 데이터가 메모리에만 저장되므로 빠르다. 즉, 속도가 느린 Disk를 거치지 않는다.

2. 데이터가 메모리에만 저장된다.

   - 당연히 프로세스가 죽거나 장비가 Shutdown되면 데이터가 사라진다.

3. 만료일을 지정하여 만료가 되면 자동으로 데이터가 사라진다.

   - 이름에서도 느껴지듯이 Cache이다

4. 저장소 메모리 재사용

   - 만료가 되지 않았더라도  더이상 데이터를 넣을 메모리가 없으면 LRU(Least recently used) 알고리즘에 의해 데이터가 사라진다.


그래서, 보통 대형 포털들에서 Static page, 또는 검색 결과 등을 캐쉬하는데 많이 사용한다.


그런데!!!!


왜!!!!! REDIS가 자꾸 Memchche와 비교되는가?


눈치들 채셨겠지만 거의 98%이상 Memchche와 동일한 기능을 제공한다.(비슷 하니까 비교 하겠지~~~)


그럼 다른 2%는 뭐냐?


이제부터 설명 들어간다..


 Memcached REDIS

처리 속도가 빠르다.

   - 당연히 데이터가 메모리에만 저장되므로 빠르다. 즉, 속도가 느린 Disk를 거치지 않는다.

처리 속도가 빠르다.

   - 당연히 데이터가 메모리+Disk에 저장된다. 그러나, 속도는 Memcached와 큰 차이가 없다.

데이터가 메모리에만 저장된다.

   - 당연히 프로세스가 죽거나 장비가 Shutdown되면 데이터가 사라진다.

데이터가 메모리+Disk에 저장된다.

   - 프로세스가 죽거나 장비가 Shutdown되더라도 Data의 복구가 가능하다.

만료일을 지정하여 만료가 되면 자동으로 데이터가 사라진다.

   - 이름에서도 느껴지듯이 Cache이다

만료일을 지정하여 만료가 되면 자동으로 데이터가 사라진다.

   - 동일한 기능을 지원한다.

저장소 메모리 재사용

   - 만료가 되지 않았더라도  더이상 데이터를 넣을 메모리가 없으면LRU(Least recently used) 알고리즘에 의해 데이터가 사라진다.

저장소 메모리 재사용 하지 않는다.

   - 명시적으로만 데이터를 제거할 수 있다.
 문자열만 지원
문자열, Set, Sorted Set, Hash, List등의 다양한 Data Type을 지원.


.. 오늘은 여기까지 하고..


사내 세미나용으로 작성한 자료 첨부 하니 참고 하세요..




REDIS intro and how to use redis from Kris Jeong

반응형

Git 이란 것을 몇달전에 알게 되었다.

한참 포켓몬고에 빠져 있을 때, 매크로 관련한 글을 우연히 보고

해당 글을 토대로 구글링한 결과!!!


사람들이 Git 이란 곳에 올려놓고 source 공유 하는 것을 보게 되었다.


코딩이란 것을 처음부터 했었던 것이고...그래서 어떤 언어든 어려움이나 거부감은 없었다.


그래서 어떤 언어로 개발되어도 이해하고 건들려고 노력을 한다. 필요하다면!!!;;;;


Anyway ~ Git을 알게 되었지만 사용법을 몰라 고생하다가 쉽게 누군가가 올려 놓은 파일만 가져다가,

xml 수정하여서 사용하다 보니 Git이 또 자연스럽게 멀어졌다.


최근에 회사 동료가 Git을 잠시 언급하길레 이때다 싶어서 물어봤더니 Source Tree 라는 툴을 이용하면 쉽게

접근 가능하다는 말에 바로 Source Tree 설치하였더니..


정말 쉽게 GUI로 접근 가능했다..물론 예전에 Git을 접할 때도 프로그램을 설치를 시도 했는데 알지 못하는 오류가

지속적으로 발생해서 포기했었다.


아래는 동영상 강의 블로그인데 강의 1개 정도만 봐도 쉽게 사용할 수 있다.


https://opentutorials.org/course/1492/8039


나도 따로 언급 안하는 이유는 Source Tree 라는 툴을 설치 후에 (그전에 Git 에 가입하는 것도 필수) 강의 한편만 봐도

쉽게 따라 할 수 있기 때문이다.


아래 이미지는 GIt에 오픈되어 있는 소스에 대한 것에 내가 Import 한 부분이고,

두번째는 내가 개발한 파이썬 스크립트를 올려 놓은 부분이다.



아무래도 Tracking 이 쉬운 게 장점이고...Private 을 위해서는 금액을 지불해야 하는 점이 단점이 아닌가 싶다..


나도 초보라 이정도만 알고 있다...;;

반응형

오랜만에 DB Guide net 에 접속했다.


그 중 Index 사용 여부에 대한 가이드 글을 읽고 느낀점에 대해서 정리해 보았다.

먼저 읽은 글의 본문은 아래와 같다.


이병국의 개발자를 위한 DB 이야기: 튜닝(31회)


개발자를 위한 DB 튜닝 실전(1편)

http://www.dbguide.net/knowledge.db?cmd=view&boardUid=192095&boardConfigUid=19&boardStep=&categoryUid=196


고작 1편보고 왜 작성하느냐...가 아니라 그동안 잠시 잊고 있었던 부분을 다시 짚는 부분과 함께,

예시 쿼리들을 직접 손으로 작성하면서 이렇게 변경해도 되는 구나 ....하기 위해서 작성하는 부분이다.




* 인덱스를 사용하는 것은 언제나 옳다???

- 답은 No 이다. 누구나 알겠지만 Full scan이 성능상 더 효과적인 경우가 있기 때문이다.


아래의 쿼리에 대해서 보자


SELECT SUM(CASE WHEN 활동구분 = ‘방문’ THEN 1 ELSE 0 END) AS 방문횟수 

       SUM(CASE WHEN 활동구분 = ‘우편’ THEN 1 ELSE 0 END) AS 우편횟수 

       SUM(CASE WHEN 활동구분 = ‘전화’ THEN 1 ELSE 0 END) AS 전화횟수 

       SUM(CASE WHEN 활동구분 = ‘SMS’ THEN 1 ELSE 0 END) AS SMS건수 

FROM 영업활동                             -- 3000만 건 이상의 대용량 테이블(10년 활동 보관)

WHERE 활동일자 BETWEEN ? AND ?          -- 조회 구간 최대 1년(인덱스 있음)

AND 활동구분 IN (‘방문’, ’우편’, ’전화’, ‘SMS’)


-  테이블 전체 건수의 1/10에 해당하는 300만 건을 추출


위의 쿼리를 인덱스를 사용하면 엄청난 시간이 소요될 수 있다. 하지만 /*+ FULL(영업활동) */  힌트를 사용하여 Full Scan을 하면 더 적게 소요될 수 있다.

이 말은 즉 데이터를 scan 시 Block 단위로 읽게(I/O) 된다. Index 를 이용하게 되면 Random access 를 하게 된다. 하지만 full scan을 하게 되면 Seqential read 하게 된다. 물론 다 그런거는 아니겠지만 대부분 Random access 하게 되면 Single block I/O 가 되며, Seqential read 하게 되면 Multi block I/O를 하게 되어 훨씬 I/O양을 줄일 수 있는 효과를 가져올 수 있다.


물론 이 내용들은 머릿속에서 엇박자로 알고 있는 부분들이라 다시 정리하게 되는 것 같다. (이해는 가지만 또 설명하게 되면 어버버 되는 상황??ㅠ)

자세한 내용은 아래에서 읽으면서 정리하는 것을 추천한다.


- I/O 효율화 원리

http://wiki.gurubee.net/pages/viewpage.action?pageId=29065463


해당 내용을 이해한다면 왜 Index를 사용안하고 Full table scan 이 더 효율적인지 이해할 수 있을 것이다.




두번째 내용은 Group by 사용과 성능 이슈 (이 부분은 기존 dbguide.net 내용을 펌~~~)


업무를 진행하다 보면 group by를 많이 사용하게 된다...내 의지와 상관없이...통계 때문일 것이다.


SELECT A.부서코드 

      , B.부서명 

      , SUM(A.판매수량) AS 판매수량 

      , SUM(A.판매금액) AS 판매금액 

FROM 판매실적 A                      -- 1천만 건 이상의 대용량 테이블(10년치 판매 실적)

     , 부서 B                          -- 수백 건 미만의 부서코드 

WHERE A.부서코드 = B.부서코드 

AND A.판매일자 BETWEEN ? AND ?      -- 조회 구간 최대 1주일(인덱스 있음)

GROUP BY A.부서코드, B.부서명 

ORDER BY A.부서코드, B.부서명 

 

여기서는 데이터 구간이 총 데이터의 1/100 , 10만건 이하이기에 인덱스를 활용해야 한다고 한다.

또한, 부서명은 order by 절에 영향을 주지 않으며, 부서 테이블은 오로지 부서명을 조회하는 용도로만 사용한다.

부서 테이블은 부서명 조회 용도이며 부서테이블과 관련한 조건절이 없다.


SELECT A.부서코드 

      , (SELECT 부서명 FROM 부서 WHERE 부서코드 = A.부서코드) AS 부서명 

      , SUM(A.판매수량) AS 판매수량 

      , SUM(A.판매금액) AS 판매금액 

FROM 판매실적 A                       -- 1천만 건 이상의 대용량 테이블(10년치 판매 실적)

WHERE A.판매일자 BETWEEN ? AND ?     -- 조회 구간 최대 1주일(인덱스 있음)

GROUP BY A.부서코드 

ORDER BY A.부서코드 


위와 같이 변경하면 부서 테이블에 대한 접근 빈도수를 최대한 줄일 수 있음.

Group by 절의 수행 이전에 부서 테이블을 접근하였으나 

개선된 쿼리는 group by 절의 수행 이후에 부서 테이블을 접근하므로 접근 빈도수가 대폭 줄어든 효과



Order by 절의 선행컬럼에 부서명이 있거나, 조건절에 부서 테이블의 컬럼이 있다면 Outer Join 방식으로 변경 불가능


SELECT A.부서코드 

      , B.부서명 

      , SUM(A.판매수량) AS 판매수량 

      , SUM(A.판매금액) AS 판매금액 

FROM 판매실적 A                        -- 1천만 건 이상의 대용량 테이블(10년치 판매 실적)

     , 부서 B                            -- 수백 건 미만의 부서코드 

WHERE A.부서코드 = B.부서코드 

AND A.판매일자 BETWEEN ? AND ?        -- 조회 구간 최대 1주일(인덱스 있음)

AND B.사용여부 = ‘Y’                     -- 현재 시점에 사용하는 부서코드 

GROUP BY B.부서명, A.부서코드 

ORDER BY B.부서명, A.부서코드


아래와 같이 인라인 뷰 방식의 쿼리로 개선 가능


SELECT A.부서코드 

      , B.부서명 

      , A.판매수량 

      , A.판매금액 

FROM 

(

    SELECT 부서코드 

          , SUM(판매수량) AS 판매수량 

          , SUM(판매금액) AS 판매금액 

    FROM 판매실적                       -- 1000만 건 이상의 대용량 테이블(10년치 판매 실적)

    WHERE 판매일자 BETWEEN ? AND ?    -- 조회 구간 최대 1주일(인덱스 있음)

    GROUP BY 부서코드 

) A, 부서 B                                -- 수백 건 미만의 부서코드 

WHERE A.부서코드 = B.부서코드 

AND B.사용여부 = ‘Y’                      -- 현재 시점에 사용하는 부서코드 

ORDER BY B.부서명, A.부서코드 


부서 테이블에 대한 접근 빈도수를 최대한 줄일 수 있었으며, Group by 절의 수행 이후에 부서 테이블을 접근하는 부분이라 접근 빈도수도 줄어드는 효과


하지만, 최종 집계된 부서의 개수가 부서코드 테이블의 전체 개수의 1/100 이상이라면 아래의 쿼리처럼 힌트절 조정을 통하여 성능 개선을 추가적으로 가능

첫번째 쿼리와 같이 Full 로 변경함으로써 성능 효과 개선 가능


SELECT /*+ FULL(B) */

       A.부서코드 

      , B.부서명 

      , A.판매수량 

      , A.판매금액 

FROM 

(

    SELECT 부서코드 

          , SUM(판매수량) AS 판매수량 

          , SUM(판매금액) AS 판매금액 

    FROM 판매실적                      -- 1000만 건 이상의 대용량 테이블(10년치 판매 실적)

    WHERE 판매일자 BETWEEN ? AND ?   -- 조회 구간 최대 1주일(인덱스 있음)

    GROUP BY 부서코드 

) A, 부서 B                              -- 수백 건 미만의 부서코드 

WHERE A.부서코드 = B.부서코드 

AND B.사용여부 = ‘Y’                    -- 현재 시점에 사용하는 부서코드 

ORDER BY B.부서명, A.부서코드


만약 조건절의 판매일자 조회 구간이 한 달 이상이라면 이번에도 인덱스를 사용치 않는 방법으로 아래와 같이 힌트를 이용해 변경 가능


SELECT /*+ FULL(A) FULL(B) */

       A.부서코드 

      , B.부서명 

      , A.판매수량 

      , A.판매금액 

FROM 

(

    SELECT 부서코드 

          , SUM(판매수량) AS 판매수량 

          , SUM(판매금액) AS 판매금액 

    FROM 판매실적                      -- 1000만 건 이상의 대용량 테이블(10년치 판매 실적)

    WHERE 판매일자 BETWEEN ? AND ?   -- 조회 구간 최대 1주일(인덱스 있음)

    GROUP BY 부서코드 

) A, 부서 B                              -- 수백 건 미만의 부서코드 

WHERE A.부서코드 = B.부서코드 

AND B.사용여부 = ‘Y’                    -- 현재 시점에 사용하는 부서코드 

ORDER BY B.부서명, A.부서코드 


조회 구간이 한달 이상이라면 대규모의 집계 처리를 의미하므로 두 테이블 모두 인덱스를 타는 것보다는 타지 않는 것이 더 선능에 좋을 것.


Group by 절의 어떠한 형식이나 어떠한 조건에 따라서 성능 개선의 방법은 다양하게 다를 수 있다. 



2번째 내용들은 이해를 하기보다는 정리 수준이라 쿼리 개발 때 참고해서 설계하는 것이 좋을 듯 싶다.



반응형

'Oracle > DBA' 카테고리의 다른 글

[Oracle] Process / Session 모니터링  (0) 2016.01.17
[펌][ORACLE] ORA-에러  (0) 2015.12.22
[Oracle] Index monitoring  (0) 2015.12.14
[Oracle] Partition Local Index 테스트  (0) 2015.12.02
[ORACLE] ASM 에 Datafile 추가  (1) 2015.11.25

MySQL 관련 Log 종류에 대해서 다시 정리해 보았다.


Binary Log 관련하여 추가 정리 및 Parameter 정리는 더 추가 해야겠다.


아래 내용들은 역활에 대해서 많이들 알고 있으며 평소에도 자주 보는 것들이다.

이것보다 더 자세한 Parameter 를 검색해서 정리하여 추가해 봐야겠다.





1. Error Log

  - log_error 파라미터에 경로 정의

  - 경로를 정의하지 않으면 daradir 파라미터에 설정된 경로에 *.err 로 생김

  - MySQL 이 시작하는 과정과 관련된 정보성 및 에러 메시지 저장

  - 마지막으로 종료할 때 비정상적으로 종료된 경우 나타나는 InnoDB의 트랜잭션 복구 메시지

  - innodb_force_recovery 파라미터를 0보다 큰 값으로 설정하고 재시작 추천

  - 쿼리 처리 도중에 발생하는 문제에 대한 에러 메시지

  - 비정상적으로 종료된 컨넥션 메시지(Aborted connection)

  - max_connect_errors 시스템 변수 값이 터무니 없이 낮을 경우 발생할 수도 있음

  - 네트워크 문제일 경우도 있음

  - InnoDB의 모니터링 명령이나 상태 조회 명령("Show Engine Innodb Status") 의 결과 메시지

  - MySQL의 종료 메시지


2. General Log file

- MySQL 서버에서 실행되는 쿼리를 기록

- 쿼리가 실행되기 전에 MySQL 이 쿼리 요청을 받으면 바로 기록하기 때문에 쿼리 실행 중 에러가 발생해도 로그파일에 기록

- 5.1.12 이전에는 "general-log" 이며, 이상에서는 "general_log_file" 로 파라미터 정의

- 5.1 이상에서는 쿼리 로그 파일이 아닌 테이블에 저장하도록 설정이 가능 -> log_output 파라미터에 의해 결정

- general log 영구 적용 

$ vi /etc/my.cnf

general_log = 1

general_log_file = /var/log/mysql_general.log

$ service mysqld restart

- mysql> set global general_log = off;


3. Slow Query log

- log_query_time 파라미터를 이용하여 초 단위로 설정 하여 이상의 시간이 소요된 쿼리가 모두 기록

- 쿼리가 정상적으로 실행이 완료 되어야 Slow Query log에 기록될 수 있음

  (정상적으로 실행이 완료됐고 실행하는 데 걸린 시간)

- slow 관련 설정은 Dynamic 으로 set global 명령으로 재시작 없이 수정 가능


mysql> show variables like 'slow%';

mysql> show variables like 'long%';

mysql> show variables like 'log%';


mysql> set global show_query_log = ON;

mysql> set global show_query_log = OFF;

mysql> set global long_query_time = 10;


  ex) 5.1 미만

   long_query_time = 1

      log_slow_queries = /var/log/mysql-slow.log

      

  ex) 5.1 이상

   log-output = File 또는 Table

   slow-query-log = 1

   long_query_time = 10

   slow_query_log_file = /var/log/mysql-slow.log


log-bin=/home/mysql_log/bin_log/bin # 빈로그 저장 설정 및 저장할 디렉토리 지정

binlog_cache_size = 2M # binlog cache 사이즈 

max_binlog_size = 50M # bin로그 최대 파일 사이즈 

expire_logs_days = 10 # 보관기간


- 인덱스를 사용하지 않는 쿼리 추출용 옵션 변수 on/off

mysql> log_queries_not_using_indexes = off

#==========================================================================================================================================

# Time : 110202 12:13:14 => 쿼리 종료 시간

# User@Host: root[root] @ localhost [] => 쿼리 실행한 사용자

# Query_time : 15.407663  => 수행시간 Lock_time : 0.000198  => Update문을 실행하기 위해 테이블 락을 기다렸다는 의미  Row_sent: 0  =>쿼리 결과의 몇건을 클라이언트로 보냈는지 표시 Rows_examined : 5  => 쿼리가 처리되기 위해 몇건의 데이터를 검색 했는지 카운트

Update tab set fd=100 where fd=10;

#==========================================================================================================================================


- MyISAM 이나 Memory Storage Engine 에서는 테이블 단위의 잠금을 사용하기에 select 쿼리도 1초 이상 소요될 가능성 있음.

- InnoDB도 select 쿼리에 대해 lock_time 이 0이 아니는 경우가 생기지만 MySQL Engine 레벨에서 설정한 테이블 잠금 때문일 가능성이 있음

- 사용자가 " Lock Table 테이블 " 명령으로 획득한 잠금에 의해서 생긴 슬로우 쿼리는 로그에 기록되지 않음

4. Binary Log와 Relay Log 

- 바이너리 로그파일은 마스터 MySQL 서버에 생성되고 릴레이 로그는 슬레이브 MySQL 서버에 생성된다는 것 말고는 바이너리 로그와 릴레이 로그 파일의 내용이나 포맷은 동일

- 바이너리 로그파일에는 Select 등의 문장은 포함되지 않고  DML 쿼리가 기록

- mysqlbinlog 를 이용하여 바이너리 파일을 텍스트로 변형 가능

ex) mysqlbinlog binlog.000012 > binlog.sql

ex) Slave와 Master 동기화 방법

- mysql> stop slave stuats;

mysql> change master to master_log_file = 'binlog.000013', master_log_pos = '443232';

mysql> start slave status;


[추가내용]


반응형

+ Recent posts