Oracle

[펌] Oracle 9.2.0 설치 (Hancom 3.0 / RedHat 9)

0


저도 Oracle 9i를 Linux 에 설치 하는 고생을 나름대로 해본 관계로 ^^;


설치하면서 적었던 기록을 올립니다. 참고가 되셨으면 좋겠습니다.


Configuration Tool에서 발생하는 에러는 “5. 설치”의 “9)” 단계에서 주의사항으로 적은 바 대로


하시면 에러가 발생하지 않습니다. 대신 Database Configuration은 실행이 안되므로 설치후


DBCA를 이용하여 설정하시면 됩니다.


 


=========================


 


1. 설치 Software 정보


 


- OS : Hancom Linux 3.0 (kernel 2.4.18-15hl) RedHat 9과 거의 같은 것으로 사료됨.


- Java : JRE 1.3.1_09


- Database: Oracle 9i Release 2 (9.2.0)


 


2. Oracle9i Database 9.2.0 버전 가져오기


 


- 홈페이지: otn.oracle.com


- 설치 파일: lnx_920_disk1.cpio.gz, lnx_920_disk2.cpio.gz, lnx_920_disk3.cpio.gz


 


3. 설치 파일 풀기


 


$ gzip d lnx_920_disk1.cpio.gz


$ cpio idmv < lnx_920_disk1.cpio


 


나머지 두개의 파일에 대해서도 같은 작업을 수행하면 Disk1, Disk2, Disk3 디렉토리가 생긴다.


 


4. 설치 준비


 


1)     J2SDK 1.3.1_09 설치 (/opt/jdk1.3.1_09)


2)     Linux 시스템 Configuration 수정


/etc/rc.d/rc.local에 추가하면 된다.


여기서는 별도의 파일 /etc/rc.d/rc.local.tuning에 저장하고 rc.local에서


이 파일을 호출하게 했다.


아래 와 같이 설정 후 rc.local.tuning 실행.


 


$ /etc/rc.d/rc.local.tuning


 






 


#


# file system options


#


 


# file-max (default: 49145) (for Oracle)


echo “65536″ > /proc/sys/fs/file-max


ulimit -n 65536


 


#


# Shared Memory (for Oracle)


#


 


# maximum size of shared memory (default: 33554432) -> 2GB


#echo “2147483648″ > /proc/sys/kernel/shmmax


echo “4294967295″ > /proc/sys/kernel/shmmax


 


# maximum number of shared memory segments in the entire system (default: 4096)


echo “4096″ > /proc/sys/kernel/shmmni


 


# maximum shared memory size to use (default: 2097152)


echo “2097152″ > /proc/sys/kernel/shmall


 


#


# Semaphores


#


 


# SEMMSL SEMMNS SEMOPM SEMMNI (default: 250 32000 32 128)


echo “250 32000 100 128″ > /proc/sys/kernel/sem


 


#


# network options


#


 


# local port range (default: 32768 61000)


echo “1024 65000″ > /proc/sys/net/ipv4/ip_local_port_range


 


 


3)     Total Memory 확인 (512MB 이상 권장)


$ grep MemTotal /proc/meminfo


 


4)     Swap space 확인 (RAM의 2배, 최소 400M 이상)


$ /sbin/swapon s


 


5)     Disk space 2.5G 이상 확인
/tmp disk space 400M 이상 확인


 


6)     file size max 설정 2G 이상 확인


$ ulimit f


 


7)     group 생성
dba group 생성.
oper group 생성.
oinstall group 생성.


 


8)      oracle user 생성.
initial group: oinstall
secondary group: dba
home: /home/oracle
shell: bash


 


9)     ~oracle/.bashrc 수정


 






 


# Environment Variables for Oracle9i


export ORACLE_BASE=”/opt/oracle”


export ORACLE_HOME=”/opt/oracle/product/9.2.0″


export ORACLE_OWNER=”oracle”


export ORACLE_SID=”ORCL”


export NLS_LANG=”AMERICAN_AMERICA.UTF8″


export ORA_NLS33=$ORACLE_HOME/ocommon/nls/admin/data


export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$ORACLE_HOME/lib


export PATH=”/opt/jdk1.3.1_09/bin”:$ORACLE_HOME/bin:


                  $ORACLE_HOME/Apache/Apache/bin:$PATH


#export TNS_ADMIN=”/home/oracle/config/9.2.0″


 


# Use old Linux threads with floating stacks instead of


# the new Native POSIX Thread Library (NPTL)


export LD_ASSUME_KERNEL=”2.4.1″


export THREADS_FLAG=”native”


 


# CLASSPATH


export CLASSPATH=$ORACLE_HOME/JRE:$ORACLE_HOME/jlib:$ORACLE_HOME/rdbms/jlib:$ORACLE_HOME/network/jlib


 


 


 


10)  binutils version 2.11.90.08-13 이상 확인


 


11)  glibc version upgrade (2.3.2-5 권장)


$ rpm -qa |grep glibc


glibc-common-2.3.2-1


glibc-debug-2.3.2-1


glibc-kernheaders-2.4-7.20


glibc-devel-2.3.2-1


glibc-2.3.2-1


glibc-debug-static-2.3.2-1


glibc-utils-2.3.2-1


glibc-profile-2.3.2-1


 


note) glibc version을 2.3.2로 맞추어야 함


ftp://ftp.hancom.com/pub/HancomLinuxOS/3.1/glibc 에서 관련 파일을 모두 받아 설치함.


rpm 설치할 때 option은 “–Uvh –nodep.


 


12)  /usr/local/bin (또는 /opt/bin) 디렉토리를 만들고 oracle user가 실행 권한을 가지도록 함.


(이 디렉토리가 PATH에 포함되어있는지도 확인)


 


13)  디렉토리 생성


$ mkdir p /opt/oracle/product/9.2.0


$ mkdir /var/opt/oracle


$ chown oracle:dba /var/opt/oracle


$ chown R oracle:dba /opt/oracle/*


$ chmod 755 /var/opt/oracle


 


14)  /etc/security/limits.conf 수정


 


아래 내용을 추가







oracle           soft     nofile           65536


oracle           hard    nofile           65536


oracle           soft     nproc           16384


oracle           hard    nproc           16384 


 


15)  GUI (X-Window) 사용이 가능한 터미널에서 설치 작업을 수행한다.


 


16)  Swing application (Oracle Universal Installer)에서 한글 폰트를 사용할 수 있도록 설정한다.


(한글 폰트 설정을 하지않으면 OUI에서 한글이 깨져 보이므로 설치를 진행할 수 없다)


 


OUI에서 사용하는 JRE는 Disk1 디렉토리에 들어있다.


/home/oracle/Disk1/stage/Components/oracle.swd.jre/1.3.1.0.0/1/DataFiles/Expanded/jre/linux/lib/


디렉토리에 font.properties.ko를 만들고, 이 디렉토리 아래 fonts 디렉토리에 한글 폰트


(백묵폰트)를 복사하고 fonts.dir 파일을 수정하였다.


 


5. 설치


 


1)     oracle 계정으로 log-in


2)     ~oracle/Disk1/runInstaller 실행.
Oracle Universal Installer 화면이 나타나면 Next를 누르고 설치 단계에 따라 적절한 설정 값을 넣어가며 설치를 진행한다.


 


3)     Inventory Location: /opt/oracle/oraInventory


4)     Unix Group Name: dba


5)     orainstRoot.sh을 실행하라는 pop-up window가 나타나면 다른 terminal을 열어 orainstRoot.sh을 실행한다.
(만일 실행 도중 /etc/oraInst.loc 파일을 만들 수 없다는 error가 나오면 root 권한 으로
touch /etc/oraInst.loc 하여 파일을 만들어주고 oraInst.loc의 owner를 oracle:dba로 만든후, orainstRoot.sh을 다시 실행한다.)


 


6)     Oracle Home Name: OUIHome
Oracle Home Path: /opt/oracle/product/9.2.0


 


7)     Select Product: Oracle9i Database


8)      Installation Type: Enterprise Edition


9)     Database Configuration: General Purpose
(주의) 만약
Software Only라는 항목이 있으면 그것을 선택한다.
뒤에 나오는 Configuration Tools 단계에서 Database Configuration을 하지 않고 넘어가게 한다.
Database Configuration은 설치 후 DBCA를 이용하여 수동으로 설정한다.
(Software Only를 선택하면 아래 10) ~ 12) 단계는 거치지 않는다)


 


10)  Database Identification:
Global Database Name: ORCL.strobus.com
SID: ORCL


 


11)  Database File Location: /opt/oracle/oradata


12)  Database Character Set: AL32UTF8 (Unicode)


 


13)  Error 발생


 







Error in invoking target install of makefile /opt/oracle/product/9.2.0/ctx/lib/ins_ctx.mk”


 


다른 터미널을 열어서 $ORACLE_HOME/ctx/lib/env_ctx.mk 파일을 편집한다.


INSO_LINK를 찾아 $(LDLIBFLAG)dl 을 추가한다.


 






INSO_LINK = -L$(CTXLIB) $(LDLIBFLAG)m $(LDLIBFLAG)dl $(LDLIBFLAG)sc_ca
 $(LDLIBFLAG)sc_fa $(LDLIBFLAG)sc_ex $(LDLIBFLAG)sc_da $(LDLIBFLAG)sc_ut
 $(LDLIBFLAG)sc_ch $(LDLIBFLAG)sc_fi $(LLIBCTXHX) $(LDLIBFLAG)c -Wl,
 -rpath,$(CTXHOME)lib $(CORELIBS) $(COMPEOBJS)


 


다시 Error window로 돌아와서 Retry버튼을 누르면 설치를 계속한다.


 


14)  Setup Privileges:
root 권한으로 root.sh을 실행하라는 pop-up window가 나타나면 새 terminal을 열어서 root 권한으로 root.sh을 실행한다. 이때 bin 디렉토리로 /usr/local/bin을 지정한다.


 


15)  Configuration Tools 화면에서 Oracle Net, Apache Web Server, Database 등의 Configuration을 진행한다. error 가 발생해도 무시한다.


16)  설치 완료 메시지가 나오면 Oracle Universal Installer를 종료한다.



 


6. 설치 후 작업


 


1)     oracle 계정으로 log-in


2)     $ cd $ORACLE_HOME/network/lib
$ make
f ins_net_client.mk install


 


3)     $ORACLE_HOME/ctx/lib/ins_ctx.mk 파일 편집


 






ctxhx: $(CTXHXOBJ)


$(LINK) $(CTXHXOBJ) $(INSO_LINK)


 


를 아래와 같이 수정.


 






ctxhx: $(CTXHXOBJ)


$(LINK) –ldl $(CTXHXOBJ) $(INSO_LINK)


 


$ make f $ORACLE_HOME/ctx/lib/ins_ctx.mk install


 


7. Database 생성


 


DBCA (Database Configuration Assistant)를 이용하여 ORCL Database를 생성한다.


 


1)     $ORACLE_HOME/bin/dbca 수정


 






if [ -f /etc/rac_on ]; then


# Run DBCA


$JRE_DIR/bin/jre -native -DORACLE_HOME=$OH -DJDBC_PROTOCOL=thin -mx64m
 -classpath $CLASSPATH oracle.sysman.assistants.dbca.Dbca $ARGUMENTS


else


# Run DBCA


$JRE_DIR/bin/jre -native -DORACLE_HOME=$OH -DJDBC_PROTOCOL=thin -mx64m
 -classpath $CLASSPATH oracle.sysman.assistants.dbca.Dbca $ARGUMENTS


fi


 


2)     $ORACLE_BASE/oradata 디렉토리를 만들어준다.


3)     $ORACLE_HOME/bin/dbca 실행


Welcome 화면이 나오면 Next.


 


4)     Operations: Create Database


5)     Database Templates: New Database


6)     Database Identification
Global Database Name: ORCL.strobus.com
SID: ORCL


7)     Database Options: Next


8)      Database Connection Options: Dedicated Server Mode


9)     Initialization Parameters
Database Character Set: KO16KSC5601
National Character Set: AL16UTF16


10)  Database Storage: Next


11)  Creation Options: Generate Database 선택하여 Database를 생성한다.
Generate Database 대신 Generate Database Creation Scripts 선택하여 /opt/oracle/admin/ORCL/scripts 디렉토리에 Database 생성 스크립트를 만들어 수동으로 Database를 만드는 경우 아래 12) ~ 14) 단계를 수행한다.
Finish 버튼 누름.


12)  스크립트를 생성하여 수동 설정을 선택한 경우: DBCA 종료 후 /opt/oracle/admin/ORCL/scripts/ORCL.sh 파일 수정.


setenv ORACLE_SID ORCL을 export ORACLE_SID=ORCL로 수정.


13)  /etc/oratab 수정 (다음 항목 추가)


ORCL:/opt/oracle/product/9.2.0:Y


14)  /opt/oracle/admin/ORCL/scripts/ORCL.sh 실행.


 


8. Starting and Stopping the Database


 


1)     Start


 






 


$ su – oracle


$ lsnrctl start


$ sqlplus /nolog


 


SQL*Plus: Release 9.2.0.1.0 – Production on ?et Svi 29 13:52:34 2003


 


Copyright (c) 1982, 2002, Oracle Corporation.  All rights reserved.


 


SQL> connect / as sysdba


Connected to an idle instance.


SQL> startup


ORACLE instance started.


 


Total System Global Area   93393176 bytes


Fixed Size                   450840 bytes


Variable Size              75497472 bytes


Database Buffers           16777216 bytes


Redo Buffers                 667648 bytes


Database mounted.


Database opened.


SQL> exit


Disconnected from Oracle9i Enterprise Edition Release 9.2.0.1.0 – Production


With the Partitioning, OLAP and Oracle Data Mining options


JServer Release 9.2.0.1.0 — Production


 


 


2)     Shut down


 






 


$ su – oracle


$ lsnrctl stop


$ sqlplus /nolog


 


SQL*Plus: Release 9.2.0.1.0 – Production on ?et Svi 29 13:55:32 2003


 


Copyright (c) 1982, 2002, Oracle Corporation.  All rights reserved.


 


SQL> connect / as sysdba


Connected.


SQL> shutdown


Database closed.


Database dismounted.


ORACLE instance shut down.


SQL> exit


Disconnected from Oracle9i Enterprise Edition Release 9.2.0.1.0 – Production


With the Partitioning, OLAP and Oracle Data Mining options


JServer Release 9.2.0.1.0 — Production


 


 


 


9. SYS 및 SYSTEM User Password 변경


 


1)     $ sqlplus /nolog


2)     SQL> connect SYS/change_on_install as sysdba


3)     SQL> ALTER USER username IDENTIFIED BY passwd ACCOUNT UNLOCK;


 


 


10. 샘플 스키마 설치


 


1)     scott User 생성


$ sqlplus system/*****


 


SQL> create user scott identified by tiger


2 default tablespace users


3 temporary tablespace temp;


 


User created.


 


SQL> grant connect , resource to scott;


Grant succeeded.


 


2)     sample table 설치


$ORACL_HOME/sqlplus/demo 디렉토리에 sample 테이블 설치를 위한 sql 파일 있음.


 


$ sqlplus scott/tiger


 


SQL>@?/sqlplus/demo/demobld


Building demonstration tables. Please wait.


 


Demonstration table build is complete.


 


Disconnected from Oracle9i Enterprise Edition Release 9.2.0.2.0 Production


With the Partitioning option


JServer Release 9.2.0.2.0 Production


 


정상적으로 설치된 경우 마지막에 sqlplus를 종료함. 다시 scott 유저로 접속한 다음 아래의 명령으로 어떤 테이블이 생성되었는지 확인.


 


$ sqlplus scott/tiger


 


SQL> select * from tab;


 






 


TNAME         TABTYPE   CLUSTERID


————- ——— ————-


BONUS          TABLE 


DEPT             TABLE 


DUMMY         TABLE 


EMP              TABLE 


SALGRADE     TABLE 


 


 


 


* 참고: Installing Oracle 9iR2 on Red Hat 9


        Oracle9i Quick Installation Procedure Release 1 (9.0.1) for Linux Intel


        Oracle9i Release Notes Release 2 (9.2.0.4.0) for Linux x86


 

[펌] mysql

0

## 원본 : mysql 3.21 Reference Manual PostScript 매뉴얼
(현재 최신 매뉴얼은 3.22 레퍼런스 매뉴얼이며 3.22.14b-gamma입니다.)

5, 6, 9, 10, 11, 12, 13, 15, 17, 18장 번역 : 문태준(taejun@hitel.net)
18장 중 C-API 부분 번역 : 권용찬 (golmong@cre.co.kr)


이메일 : taejun@hitel.net, taejun@taejun.pe.kr
웹 : http://taejun.pe.kr (Mysql 관련 자료가 모아져 있습니다)

자료를 공유하기 편하도록 홈페이지를 열었습니다.
많이 애용해주시면 감사~하겠습니다.


개인적인 질문은 각 통신망의 리눅스 동호회나 인터넷을 참고하세요.

**로 묶인 것은 제가 주를 단 것입니다.

설치와 관련된 부분은 kldp.org의 database 항목에서 관련된 정보가 있으므로 참고하시면 됩니다.



0. 목차
1. MySQL 일반 정보
2. MySQL 메일링 리스트 및 질문 요청 방법, 에러(버그) 알리기
3. 라이센싱 / mysql에 지불해야 할 경우
4. mysql 설치
5. mysql의 표준 호환성
6. mysql 접근 권한 시스템
7. mysql 언어 레퍼런스
8. SQL 질의 예제
9. mysql 서버 기능
10. mysql의 최대 성능 향상 방법
11. mysql 벤치마크
12. mysql 유틸리티
13. 테이블 유지보수 및 파손 복구에 isamchk 사용하기
14. mysql에 새로운 기능 추가
15. mysql ODBC 지원
16. 일반적인 문제 및 에러
17. 일반적인 문제 해결 방법
18. mysql 클라이언트 툴과 API
19. 다른 데이터베이스와 비교

부록 A ; MYSQL 사용자
부록 B ; 개발 프로그램
부록 C ;MYSQL 개발자
부록 D ; MYSQL 버전업 역사
부록 E ; MYSQL의 알려진 에러 및 설계에서 부족한 부분
부록 F ; MYSQL에 장래 추가할내용(The TODO)
부록 G ; 다른 시스템에 포팅하기
부록 H ; MYSQL 정규표현식 설명
부록 I ; Unireg 설명
부록 J ; 비MS 운영체제에서 MYSQL 서버 라이센스
부록 K ; MS 운영체제에서 MYSQL 라이센스
SQL 명령, 타입, 함수 인덱스
개념 인덱스

1. MySQL 일반 정보
1.1 MYSQL은 무엇인가?
1.2 매뉴얼에 관하여
        1.2.1 매뉴얼에서 쓰인 규정
1.3 MYSQL 역사
1.4 주요특징
1.5 안정성
1.6 2000년 문제
1.7 일반적인 SQL 정보 및 참고자료
1.8 관련 링크

2. MySQL 메일링 리스트 및 질문 요청 방법, 에러(버그) 알리기
2.1 mysql 메일링 리스트
2.2 질문하기, 버그 알리기
2.3 버그나 문제를 알리는 방법
        2.3.1 mysql이 손상되었을때
2.4 메일링리스트에서 질문 답변에 대한 안내

3. 라이센싱 / mysql에 지불해야 할 경우
3.1 mysql 비용
3.2 상업적인 지원 방는 방법
        3.2.1 기본 이메일 지원
        3.2.2 확장 이메일 지원
        3.2.3 login 지원
        3.2.4 확장 login 지원

3.3 라이센싱이나 지원에 지불하는 방법
3.4 라이센싱/지원 관련 정보 담당자
3.5 사용자 저작권 관련
3.6 mysql에 요금을 내지 않고 상업적으로 판매하는 경우
3.7 mysql을 사용해야 설정할 수 있는 제품을 판매하는 경우
3.8 mysql을 사용하여 상업적인 웹 서버를 운영하는 경우
3.9 상업용 Perl/Tcl/PHP/기타 애플리케이션을 판매하는 경우
3.10 앞으로의 라이센싱 변화

4. mysql 설치
4.1 mysql 구하기
4.2 mysql에서 지원하는 운영체제
4.3 사용할 수 있는 mysql 버전
4.4 업데이트 방법 및 시기
4.5 설치 개괄
4.6 바이너리로 설치하기
        4.6.1 클라이언트 프로그램 만들기
        4.6.2 시스템 관련 참고사항
                4.6.2.1 리눅스
                4.6.2.2 HP-UX
4.7 소스로 설치하기
        4.7.1 빠른 설치
        4.7.2 패치 적용하기
        4.7.3 일반 설정 옵션
4.8 컴파일에서 문제점이 생길때
4.9 MIT-pthreads 주의사항
4.10 펄 설치
        4.10.1 펄 DBI/DBD 인터페이스 사용시 문제점
4.11 시스템 관련 참고사항
        -솔라리스, 솔라리스 x86, 선OS4, 알파-DEC-유닉스, 알파-DEC-OSF1,
         SGI-IRIX, FreeBSD, BSD/OS 2, SCO, SCO Unixware 7.0, IBM-AIX, HP-UX
        -리눅스 : 리눅스-x86, 레드햇 5.0/5.1, 리눅스-스팍,리눅스-알파,MkLinux
         리눅스 RPM
4.12 TcX 바이너리
4.13 Win32 관련사항
4.14 설치후 셋업 및 테스트
        4.14.1 mysql_install_db 실행시 문제점
        4.14.2 mysql 서버 실행시 문제점
        4.14.3 자동 시작/정지 시키기
        4.14.5 옵션 파일
4.15 업그레이드/다운그레이드할때의 주의사항
        4.15.1 3.21에서 3.22로 업그레이드
        4.15.2 3.20에서 3.21로 업그레이드
        4.15.3 다른 아키텍쳐로 업그레이드

5. mysql의 표준 호환성
5.1 mysql의 ANSI SQL92 확장 부분
5.2 mysql에서 빠진 기능
        5.2.1 sub-selects
        5.2.2 SELECT INTO TABLE
        5.2.3 트랜잭션
        5.2.4 저장 프로시져/트리거
        5.2.5 외래키
                5.2.5.1 외래키 사용하지 않는 이유
        5.2.6 뷰
        5.2.7 ‘–’ 로 주석문 시작
5.3 mysql에서 따르고 있는 표준
5.4 BLOB/TEXT 타입의 제한사항
5.5 COMMIT-ROLLBACK 없이 사용하는 방법

6. mysql 접근 권한 시스템
6.1 접근 권한 시스템이란 무엇인가
6.2 mysql 서버에 연결하기
        6.2.1 비밀번호를 안전하게 유지하기
6.3 mysql에서 제공하는 권한
6.4 권한 시스템 작동 방식
6.5 접근 제어 1 : 연걸 인증
6.6 접근 제어 2 : 요청 인증
6.7 권한변경시 적용 방법
6.8 초기 mysql 권한 설정
6.9mysql에 새로운 사용자 권한 추가
6.10 비밀번호 설정 방법
6.11 접근 금지 에러가 나는 이유
6.12 크랙커에 대비하여 mysql을 안전하게 만드는 방법

7. mysql 언어 레퍼런스
7.1 문자 : 문자열과 숫자 기록하기
        7.1.1 문자열
        7.1.2 숫자
        7.1.3 NULL 값
        7.1.4 데이터베이스, 테이블, 인덱스, 컬럼, 알리아스 이름
                7.1.4.1 이름에서 대소문자 구별
7.2 컬럼 타입
        7.2.1 컬럼 타입 저장 요구량
        7.2.2 숫자 타입
        7.2.3 날짜/시간 타입
                7.2.3.1 DATETIME, DATE, TIMESTAMP 타입
                7.2.3.2 TIME 타입
                7.2.3.3 YEAR 타입
        7.2.4 문자열 타입
                7.2.4.1 CHAR, VARCHAR 타입
                7.2.4.2 BLOB, TEXT 타입
                7.2.4.3 ENUM 타입
                7.2.4.4 SET 타입
        7.2.5 컬럼에 적절한 타입 고르기
        7.2.6 컬럼 인덱스
        7.2.7 다중 컬럼 인덱스
        7.2.8 다른 데이터베이스 엔진의 컬럼 타입 사용
7.3 SELECT 와 WHERE 문에서의 함수(functions)
        7.3.1 그룹(Group)으로 묶는 기능
        7.3.2 산술연산자
        7.3.3 비트(Bit) 함수
        7.3.4 논리(logical) 연산자
        7.3.5 비교 연산자
        7.3.6 문자열 비교 함수
        7.3.7 흐름 제어(control flow) 함수
        7.3.8 산술 함수
        7.3.9 문자열 함수
        7.3.10 날짜/시간 함수
        7.3.11 기타 함수
        7.3.12 GROUP BY 문에서 사용하는 함수
7.4 CREATE DATABASE
7.5 DROP DATABASE
7.6 CREATE DATABASE
        7.6.1 자동 컬럼 변환
7.7 ALTER TABLE
7.8 OPTIMIZE TABLE
7.9 DROP TABLE
7.10 DELETE
7.11 SELECT
7.12 JOIN
7.13 INSERT
7.14 REPLACE
7.15 LOAD DATA INFILE
7.16 UPDATE
7.17 USE
7.18 FLUSH(캐쉬 삭제)
7.19 KILL
7.20 SHOW(테이블, 컬럼 정보 얻기)
7.21 EXPLAIN(SELECT 관련 정보 얻기)
7.22 DESCRIBE(컬럼 정보 얻기)
7.23 LOCAK TABLES/UNLOCK TABLES
7.24 SET OPTION
7.25 GRANT / REVOKE
7.26 CREATE INDEX(호환성 기능)
7.27 DROP INDEX(호환성 기능)
7.28 주석
7.29 CREATE FUNCTION/DROP FUNCION
7.30 예약된 문자 사용하는 경우

8. SQL 질의 예제
        8.1 twin project에서의 질의
                8.1.1 Find all non-distributed twins
                8.1.2 Show a table on twin pair status

9. mysql 서버 기능
        9.1 mysql에서 지원하는 언어
                9.1.1 데이터와 정열에 사용하는 문자 셋
                9.1.2 새로운 문자셋 추가
                9.1.3 멀티바이트 문자 지원
        9.2 업데이트 로그
        9.3 mysql 테이블 최대 크기

10. mysql의 최대 성능 향상 방법
10.1 버퍼 크기 조정
10.2 메모리 상용 방법
10.3 속도 향상에 영향을 미치는 컴파일/링크 방법
10.4 인덱스 사용방법
10.5 WHERE 문에서 최적화하기
10.6 테이블 열고 닫는 방법
        10.6.1 데이터베이스에서 많은 수의 테이블을 만들때의 단점
10.7 많은 테이블을 여는 이유
10.8 데이터베이스와 테이블에서 심볼링 링크 사용
10.9 테이블에 락 거는 방법
10.10 테이블을 빠르고 작게 배열하는 방법
10.11 INSERT 문에서 속도에 영향을 미치는 부분
10.12 DELETE 문에서 속도에 영향을 미치는 부분
10.13 mysql에서 최대 속도를 얻는 방법
10.14 로우 포맷과 다른 점은 무엇인가? 언제 VARCHAR/CHAR을 사용해야 하는가?

11. mysql 벤치마크

12. mysql 유틸리티
        12.1 서로 다른 mysql 프로그램 개괄
        12.2 텍스트 파일에서 데이터 가져오기
        12.3 mysql 압축 읽기 전용 테이블 생성기

13. 테이블 유지보수 및 파손 복구에 isamchk 사용하기
        13.1 isamchk 명령어 사용법
        13.2 isamchk 메모리 사용법
        13.3 테이블 유지보수 설정
        13.4 테이블에서 정보 얻기
        13.5 파손 복구에 isamchk 사용하기
                13.5.1 에러가 났을때 테이블 점검 방법
                13.5.2 테이블 복구 방법
                13.5.3 테이블 최적화하기

14. mysql에 새로운 기능 추가
        14.1 새로운 사용자 정의 기능 추가
                14.1.1 UDF calling sequences
                14.1.2 Argument processing
                14.1.3 Return values and error handling
                14.1.4 사용자 정의 기능 컴파일 및 설치하기

        14.2 새로운 native 기능 추가

15. mysql ODBC 지원
        15.1 MyODBC가 지원하는 운영체제
        15.2 MyODBC에 문제가 있을때
        15.3 MyODBC와 작동하는 프로그램
        15.4 ODBC 관리자 프로그램 설정 방법
        15.5 ODBC에서 AUTO_INCREMENT 컬럼의 값 가져오기

16. 일반적인 문제 및 에러
        16.1 mysql 사용시 일반적인 에러
                16.1.1 mysql 서버가 맛이 간 경우
                16.1.2 local mysql 서버에 접속이 안되는 경우
                16.1.3 Host ‘…’ is blocked 에러
                16.1.4 Out of Memory 에러
                16.1.5 Packet too large 에러
                16.1.6 The table is full 에러
                16.1.7 Commands out of sync 에러(클라이언트)
                16.1.8 Ignoring user 에러
                16.1.9 Table ‘xxx’ doesn’t exist 에러
        16.2 mysql에서 디스크가 꽉 찼을때
        16.3 텍스트 파일에서 SQL 문장 실행하기
        16.4 mysql에서 임시 파일을 저장하는 곳
        16.5 /tmp/mysql.sock을 지워지지 않도록 보호하는 방법
        16.6 Access denied 에러
        16.7 일반 사용자로 mysql 실행하기
        16.8 파일 퍼미션 문제
        16.9 File not found
        16.10 DATE 컬럼 사용할때 문제
        16.11 검색에서 대소문자 구별
        16.12 NULL 값에서 문제
        16.13 alias에서 문제
        16.14 관련된 테이블에서 레코드를 지웠을때
        16.15 해당하는 레코드가 없을때 문제 해결
        16.16 ALTER TABLE 에서 문제

17. 일반적인 문제 해결 방법
        17.1 데이터베이스 복사
        17.2 데이터베이스 백업
        17.3 같은 머신에서 여러개의 mysql 서버 실행하기

18. mysql 클라이언트 툴과 API
        18.1 mysql C API
        18.2 C API 테이타타입
        18.3 C API 함수 개괄
        18.4 C API 함수 설명
                **생략**
                18.4.47 mysql_query()가 성공했는데도 mysql_store_result()
                        가 NULL을 반환하는 경우
                18.4.48 질의에서 결과 얻는 방법
                18.4.49 마지막으로 입력된 unique ID 얻는 방법
                18.4.50 C API와 링크할때 문제점
                18.4.51 thread-safe 클라이언트 만들기
        18.5 mysql perl API
                18.5.1 DBI with DBD :: mysql
                        18.5.1.1 dbi 인터페이스
                        18.5.1.2 DBI/DBD 추가 정보
        18.6MYSQL 자바 연결(JDBC)
        18.7 mysql PHP API
        18.8 MYSQL C++ API
        18.9 mysql Python API
        18.10 Mysql TCL API

19. 다른 데이터베이스와 비교
        19.1 mSQL과의 비교
                19.1.1 mSQL 툴을 mysql로 옮기기
                19.1.2 msql과 mysql 클라이언트/서버 통신 프로토콜의 차이점
                19.1.3 msql 2.0과 mysql의 SQL 문 차이점
        19.2 PostgreSQL과의 비교


부록 A ; MYSQL 사용자
부록 B ; 개발 프로그램
부록 C ;MYSQL 개발자
부록 D ; MYSQL 버전업 역사
부록 E ; MYSQL의 알려진 에러 및 설계에서 부족한 부분
부록 F ; MYSQL에 장래 추가할내용(The TODO)
부록 G ; 다른 시스템에 포팅하기
부록 H ; MYSQL 정규표현식 설명
부록 I ; Unireg 설명
부록 J ; 비MS 운영체제에서 MYSQL 서버 라이센스
부록 K ; MS 운영체제에서 MYSQL 라이센스
SQL 명령, 타입, 함수 인덱스
개념 인덱스
5. mysql의 표준 호환성

5.1 mysql의 ANSI SQL92 확장부분
mysql에는 다른 sql 데이터베이스에서 찾을 수 없는 확장된 부분이 있다. 이런 부분을 사용
하는 경우 주의해야 한다. 왜냐면  mysql에서 사용한 코드가 다른  SQL 서버에 포팅할 수
없을 수도 있기 때문이다. 어떤 경우에는 /*! … */ 형식의 주석문을 사용한 MYSQL 확장을
이용해 포팅가능한 코드를 만들 수 있다. 예를 들어보자:

SELECT /*! STRAIGHT_JOIN */ col_name from table1,table2 WHERE …

MYSQL의 확장 부분은 다음과 같다:
- 필드타입 MEDIUMINT, SET, ENUM , 그리고 다른 BLOB 와 TEXT 타입.
- 필드속성 AUTO_INCREMENT, BINARY, UNSIGNED and ZEROFILL.
- 모든 문자열 비교는 기본적으로  대소문자를 구별하지 않으며 현재의  문자셋(기본적으로
ISO-8859-1 Latin1)에 의해 정렬 순서가 결정된다. 이것을 원하지 않으면  컬럼을 BINARY
속성으로 정의해야 하며 이런 경우에는 mysql 서버 호스트가 사용하는 ASCII 순서에 따라
문자열을 비교한다.
- MYSQL은 데이터베이스를 디렉토리로 만들고 테이블은 파일이름으로 만든다. 이것은 두
가지를 함축하고 있다:
    ㅇ 파일이름의 대소문자를 구별하는 (대부분의  유닉스 시스템. 리눅스도 마찬가지겠지
     용~) 운영  시스템에서는 MYSQL의 데이터베이스 이름과  테이블 이름은 대소문자를
     구별한다. 테이블 이름을 기억하는데 문제가 있다면 모든 것을 소문자로 만들자.
    ㅇ 테이블의 백업, 이름바꾸기, 옮기기, 삭제,  복사를 위해 표준 시스템 명령을  사용할
     수 있다. 예를 들어 테이블의 이름을 바꾸려면  해당하는 테이블의 `.ISD’, `.ISM’ and
     `.frm’ 파일의 이름을 바꾸면 된다.
- SQL문에서 db_name.tbl_name 문을 이용하여  다른 데이터베이스의 테이블에 접근할  수
있다. 일부 SQL 서버는 같은 기능을 지원하지만 이것을 User space라고 부른다. MYSQL은
다음과  같은  TABLESPACES를  지원하지  않는다  :  create  table  ralph.my_table…IN
my_tablespace.
- 수치(숫자형) 컬럼에서 LIKE를 사용할 수 있다.
- SELECT문에서   INTO OUTFILE  과  STRAIGHT_JOIN  을 사용할   수 있다.  7.11
[SELECT] 참고.
-EXPLIAN SELECT는 테이블에서 어떻게 조인이 되었는지에 대한 정보를 보여준다.
- Use of index names, indexes on a subpart of a field, and use of INDEX or KEY in a
CREATE TABLE statement. 7.6 [CREATE TABLE] 참고.
- ALTER TABLE에서 CHANGE col_name, DROP col_name 또는 DROP INDEX 를 사용
한다. 7.7 [ALTER TABLE] 참고.
- ALTER TABLE 문에서 IGNORE 사용.
- ALTER TABLE 문에서 다중 ADD, ALTER, DROP or CHANGE 사용
- IF EXISTS 키워드를 이용한 DROP TABLE 사용.
- 한 테이블 이상에서 DROP TABLE 사용.
- LOAD DATA INFILE 사용. 대부분의 경우 이 문장은  오라클의 LOAD DATA INFILE
과 호환된다. 7.15 [LOAD DATA INFILE] 참고.
(** 많은 양의 데이터를 한꺼번에 입력할 때 일일이 INSERT 문을 하는  것보다 속도가 빠
르다. **)
- OPTIMIZE TABLE 문 사용.
- 문자열은 ”’ 만이 아니라 ‘”‘ 또는 ”’ 로 닫을 수 있다.
- escape `\’ 문자 사용.
- SET OPTION 문. 7.24 [SET OPTION] 참고.
- GROUP BY 부분에서 모든 컬럼을 사용할 필요가 없다. 이러한  기능은 일반적인 질의가
아닌 특정한 질의에서 성능을 향상시킨다. 7.3.12 [GROUP BY Functions] 참고.
(** ANSI SQL에서는 여러 테입믈을 이용하여 GROUP  BY를 사용할 때 사용하고자 하는
모든 컬럼에 GROUP BY를 지정해 주어야 한다. 이렇게 되는 경우 불필요한 연산이 수행될
수 있는데 MYSQL에서는 이러한 것을 없앤 것이다. 7.3.12를 참고한다 **)
- 다른 SQL 환경을 사용했던 사용자를 위해 MYSQL은 많은  기능에서 알리아스를 지원한
다. 예를 들어 모든 문자 펑션은 ANSI SQL 과 ODBC 구문을 지원한다.
- MYSQL은 C 프로그래밍 언어와 같은 논리적인 OR 과 AND를 의미하는 || 와 && 를 인
식한다. MYSQL에서는 || 와 OR 는 같은 말이며 && 와 AND 도 마찬가지이다. 이러한 미
묘한 구문때문에 MYSQL은 string  concatenation(문자열 연관, 연결?)을 위한  ANSI SQL
오퍼레이터인 || 을 지원하지 않는다. 대신 CONCAT()를 사용한다. CONCAT() 는 많은 인
자가 있어서 MYSQL 에서 || 오퍼레이터의 사용을 변환하기 쉽다.

MySQL understands the || and && operators to mean logical OR and AND, as in the C
programming language. In  MySQL, ||  and OR are  synonyms, as  are &&  and AND.
Because of this  nice syntax,  MySQL doesn’t support  the ANSI  SQL operator  || for
string concatenation; use  CONCAT() instead.  Since CONCAT() takes  any number  of
arguments, it’s easy to convert use of the || operator to MySQL.

- 포팅이 가능하도록 SQL CODE에서  STRAIGHT_JOIN같은 MYSQL만의 키워드 사용을
지원하기 위해 이런 키워드를 /* */ 주석안에 내장할 수 있다. 주석문안의 내용은 ‘!’ 로 시
작한다. 이런 경우  MYSQL에서는 주석문을 다른  MYSQL 구문과 같이  해석하지만 다른
SQL 서버에서는 이러한 확장기능을 사용하지 않고 건너띌 수 있다. 예를 보자:

SELECT /*! STRAIGHT_JOIN */ * from table1,table2 WHERE …

- 다음의 기능이나 명령 사용:
    ㅇ CREATE DATABASE or DROP DATABASE. 7.4 [CREATE DATABASE] 참고.
    ㅇ MOD() 대신에 % 사용. %는 C 프로그래머를 위해 지원하며 또한 PostgresSQL과의
     호환성을 위해 지원한다.
    ㅇ 컬럼 문에서 =, <>, <= ,<, >=,>, <<, >>, AND, OR, LIKE 사용.
    ㅇ LAST_INSERT_ID(). 18.4.49 [mysql_insert_id()] 참고.
    ㅇ REGEXP or NOT REGEXP.
    ㅇ 하나나 하나 이상의 인자를 사용한 CONCAT() 나 CHAR(). MYSQL에서 이러한 펑
     션은 여러개의 인자를 가질 수 있다.
    ㅇ  BIT_COUNT(),   ELT(),  FROM_DAYS(),   FORMAT(), IF(),   PASSWORD(),
     ENCRYPT(), PERIOD_ADD(), PERIOD_DIFF(), TO_DAYS(), or WEEKDAY().
    ㅇ 서브스트링을 없애는 데 TRIM()  사용.(Use of TRIM() to trim  substrings) ANSI
     SQL 에서는 단일 문자 제거만 지원한다.
(** 꺼어억~ 트림이 술먹고 하는 트림은 아니랍니다… **)
ㅇ 그룹 펑션에서 STD(), BIT_OR() and BIT_AND()
ㅇ DELET + INSERT 대신 REPLACE 사용. 7.14 [REPLACE] 참고.
ㅇ FLUSH flush_option 명령.


5.2 MYSQL에서 빠진 기능
다음의 기능들은 현재 버전의 MYSQL에  빠져있다. 다음 버전에서의 우선권을 확인하라면
MYSQL TODO 목록을  참고하자(http://www.mysql.com/Manual_split/manual_Todo.html).
이것이 가장 최신 버전의 TODO 목록이다. 부록 F [TODO] 참고.

5.2.1 Sub-selects
다음은 Mysql에서 작동하지 않는다:

SELECT * FROM table1 WHERE id IN (SELECT id FROM table2);

Mysql에서는 오직 INSERT … SELECT … and  REPLACE … SELECT … 만을 지원한다.
독립적인 서브-select 문은 3.23.0에서 아마도 사용할 수 있을 것이다.  그대신 현재 IN() 펑
션을 사용할 수 있다.

5.2.2 SELECT INTO TABLE
Mysql은 아직  SELECT …  INTO TABLE  ….을 지원하지  않는다. 현재,  Mysql은 오직
SELECT … INTO OUTFILE …, 만을 지원하며 기본적으로는 동일하다.

5.2.3 트랜잭션(Transactions)
트랜잭션은 지원되지  않는다. Mysql은  곧 atomic(원자성?)  오퍼레이션을 지원할  것이며
atomic 오퍼레이션은 rollback이 없는 트랜잭션과 비슷하다.  atomic 오퍼레이션을 사용하며
insert/select/모든 명령의 그룹을 실행할 수 있으며 어떤 스레드도 충돌하지 않을 수 있도록
보장해준다. 이 문맥에서 일반적으로 롤백(rollback)은  필요없다. 현재 LOCK TABLES  와
UNLOCK TABLES 명령을  이용하여 다른  스레드가 충돌하는 것을  막을 수  있다. 7.23
[Lock Tables] 참고.

5.2.4 저장 프로시저와 트리거
저장 프로시저는 서버에서 컴파일되고 저장될 수 있는 SQL 명령 세트이다. 이런 기능이 수
행되면 클라이언트는 전체 질의를 다시 할 필요가 없고 또한 저장 프로시저를 참조할 수 있
다. 이런 기능이 있으면 질의는  한번만 해석되고 서버와 클라이언트간의  주고받아야 하는
데이터가 줄어들므로 속도가 향상된다. 또한 서버의  펑션 라이브러리를 가짐으로서 개념적
인 단계를 향상시킬  수 있다. (???  You can also  raise the conceptual  level by  having
libraries of functions in the server.)

트리거는 특별한 이벤트가 발생했을 때 생기는 저장 프로시져이다.  예를 들어 트랜잭션 테
이블에서 레코드가 삭제되고 모든 트랜잭션이 지워질 때 상응하는 테이블을 삭제할 수 있는
저장 프로시저를 설치할 수 있다.

앞으로는 저장 프로시저를 지원할 예정이지만 트리거는 아니다. 트리거는 필요하지 않은 경
우에도 사용될 수 있어서 일반적으로 속도가 느려진다.

언제 저장 프로시저를 사용하게  될지는 앞으로 Mysql에 추가할  목록인 부록 F를 참고하
자.(The TODO)

(** 전반적으로 트랜잭션 처리와 트리거 등은 데이터베이스의 속도를 저하시킵니다. Mysql
은 이렇게 속도에 영향을 미칠 수 있는 부분을 제거하여  빠른 속도를 내는 것이지요. 이러
한 부분이 자기가 사용하는 데이터베이스에서 얼마나 중요한가 판단을 해 보아야 할 것입니
다. 보통 소형 DBMS에서는 회복과 병행수행을 지원하지 않는 경우가 많다. 즉 병행수행은
발생하지 않으며, 회복은 사용자의 문제로 생각한다. 그러므로 사용자가 데이터베이스의  예
비 사본을 준비하며, 고장이 발생하면 작업을 다시 해야 한다. 트리거같은 경우는 자료의 무
결성을 보장하기 위해 필요한 것이다. **)

5.2.5 외래키(Foreign Keys)
SQL 문에서 외래키는 테이블을 조인할 때  사용하지 않지만 대부분 참조 무결성을 확인할
때 사용한다. SELECT 문에서 다중 테이블에서 자료를 가져오길 원하면 테이블을 조인해서
처리할 수 있다.

SELECT * from table1,table2 where table1.id = table2.id

7.12 [JOIN] 참고.

Mysql에서 외래키(FOREIGN KEY) 문은 다른 SQL 제품의 CREATE TABLE 명령과의 호
환성 때문에   존재한다: 외래키는   아무것도 하지  않는다.  ON  DELETE  …  가  없는
FOREIGN KEY 구문은 대부분 문서적인  목적으로 사용한다. 일부 ODBC  애플리케이션은
이것을 자동적인 WHERE 문을 만들 때 사용할 것이다. 그렇지만 이것은 대부분 생략(무시)
하고 넘어가기 쉽다. 외래키는 때로는 제약조건 체크(constraint check)로 사용을 하지만 이
러한 체크는 데이터가 테이블에 정확한 순서로 들어갈때는 불필요하다. Mysql은 일부 애플
리케이션에서 외래키가 존재하는 것을 필요로 하기 때문에(제대로 작동하든  안하든 상관없
이) 지원하는 것일 뿐이다.

Mysql에서 외래키를 가진 테이블의 레코드를  삭제할 때 애플리케이션에 적절한 DELETE
문을 추가하여 ON DELETE … 가 수행되는 것을  막음으로써 문제를 해결할 수있다. 경험
상 이렇게 하는 것이 외래키를 사용하는 것과 같이 빠르며(어떤  경우에는 더 빠름) 포팅하
기가 더 좋다.

가까운 시일안에 우리는 외래키 기능을 확장할 것이다. 그래서 최소한 mysqldump와 ODBC
에서 정보가 저장되고 검색할 수 있도록 할 것이다.


5.2.5.1 외래키를 사용하지 않는 이유

외래키를 사용할 때 어디에서 출발해야 할지 모르는 많은 문제가 있다:

- Foreign key들은 상황을 매우 복잡하게 만든다. 왜냐하면, foreing key의 정의가 database에
담겨야 하고, foreign key를 구현하는 것은 “자연스런” File 사용법(data file들을 옮기고,
복사하고, 삭제하는 등…)을 제한한다.
(** 문태준님 역주: 번역이 이상한데 외래키가 있으면 참조 무결성 규칙을 위해 여러 가지
보상  연산을 하게 된다. 이것을 뜻하고 있는 듯하다. **)

- INSERT 와 UPDATE 문은 속도에 많은 영향을  끼친다. 그리고 이런 경우 보통 올바른
순서로 올바른 테이블에 레코드를 삽입하기 때문에 대부분 모든 외래키 체크는 사용할 필요
없다.

- 한쪽의 영향이 전체 데이터베이스에 연쇄 작용을 하기 때문에 테이블에서 업데이트를 할
때 매우 많은 테이블에서 락을 사용해야 한다. 한 테이블에서 먼저 레코드를 삭제하고 그후
에 다른 테이블에서 레코드를 삭제하는 것이 훨씬 빠르다.

- Table를 완전히 지우고, (backup이나 새로운 source로부터) 모든 record들을 다시 복구하는
방법으로 Table을 복구할 수 없다.

- Foreign key를 사용한다면, table을 dump(backup)하고 (그 dump한 자료를) restore하는 데
있어 그 일련의 순서를 적절하게 지켜야 한다.

- 각각의 table의 정의가 쓸모있고 적절하더라도, (각 Table들이 상호참조하게 된다면) 단순한
create문으로는 재생성이 불가능한 circular definition(순환정의)가 쉽게 발생한다.
(역자주: A라는 Table이 B의 자료를 참조하는 foreign key를 담고 있고,
         B는 C에 대한 foreign key를, C는 A에 대한 foreign key를 담도록 table이 구성된다면
         한번에 A,B,C table을 생성할 수 없다. A,B,C를 만든다음 각각의 foreign key를 지정해
         주는 방법을 쓰게 된다.)

외래키의 좋은 점은 단지 다음와 같다. ODBC와  특정한 다른 클라이언트 프로그램에서 어
떻게 테이블이 연결되어 있는지를 볼 수 있고 연결 다이어그램을 보는데 사용하며 애플리케
이션을 만드는데 돕는 점이다.
(역자주: 이 글은 foreign key에 대해서 매우 비판적이다. 하지만, 이것은 foreign key의
         일부 기능일뿐이다. 무엇보다도 client가 각 Table내 DATA의 연관관계에 대해서
         빼먹었는지에 대해서 일일이 신경쓰지 않게 하고, 항상 자료의 무결성(정합성[?])을
         보장한다는 것은 매우 중요하다.

         특히, Table이 1~20개가 아닌 100단위가 넘어간다면, client에서 일일이 신경쓰며
         programing하는 것도 힘들지만, debugging도 예상보다 힘들어진다.
         각 table간의 연결관계를 잘 문서화한다면 programmer들이 foreign key로 고통받기
         보다는 관련 Table을 check해야 되는 수고를 덜게된다.

         foreign key가 기피되는 주된 이유는 table내의 Data를 수정하는 것이 쉽지 않기
         때문이다. 현장 실무자의 논리에 어긋나는 요청을 처리하는 데 있어서
         foreign key만큼 거추장스런 놈도 없으리라. )

Mysql에서는 곧 외래키 정의를 저장할 수 있도록 해서 클라이언트가 어떻게 원래의 연결이
만들어졌는지에 대해서 질문하고 답을 받을 수 있도록 할 것이다. 현재의  ‘.frm’ 파일 포맷
은 아직 이것을 지원하지 못하고 있다.


5.2.6 뷰

Mysql은 뷰를 지원하지 않는다. 그렇지만 TODO(이후 개선 목록)에 있다.
MySQL doesn’t support views, but this is on the TODO.

5.2.7 `–’을 사용한 주석

일부 다른 SQL 데이터베이스는 ‘–’  로 주석을 시작한다. mysql 명령  라인 도구가 ‘–’로
시작하는 모든 줄을 제거할 지라도 Mysql은  ‘#’을 주석 문의 시작으로 사용한다.  사용자는
또한 C 명령  스타일인 /*  this is  a comment  */ 를  mysql에서 사용할  수 있다.  7.28
[Comment] 참고.

Mysql은 ‘–’를 지원하지  않을 것이다;  ‘–’은 퇴보한  주석문 형태로 자동으로  생성되는
SQL 질의에서 많은 문제를 발생시킨다. 다음의 예제를 보자. 우리는 자동적으로 payment를
!payment! 의 값으로 입력하도록 하고 있다 :

UPDATE tbl_name SET credit=credit-!payment!

payment의 값이 음수일 때 어떤 일이 생길 것이라 생각하는가?

1–1은 합당한 SQL문이기 때문에 ‘–’가 주석문의 시작을 의미하는 것을 꺼리는 것이다.

‘–’ 주석을 포함하는 텍스트 파일의 SQL 프로그램을 가졌다면 다음과 같이 사용해야 한다:

shell> replace ” –” ” #” < text-file-with-funny-comments.sql \
         | mysql database

instead of the normal(정상적인 경우 대신???):

shell> mysql database < text-file-with-funny-comments.sql

명령 파일로 ‘–’ 주석을 ‘#’ 주석으로 바꿀 수 있다:

shell> replace ” –” ” #” — text-file-with-funny-comments.sql

다음의 명령으로 원래대로 돌려놓자:

shell> replace ” #” ” –” — text-file-with-funny-comments.sql

(** 일부 SQL에서 사용하는 –  주석문에서 문제가 생길 수 있으므로  MYSQL에서는 #을
주석문으로 사용한다는 말이다 **)

5.3 Mysql이 따르고 있는 표준은 무엇인가?

Entry level SQL92. ODBC level 0-2.


5.4 BLOB 와 TEXT 타입의 제한
BLOB 나 TEXT 필드에서 GROUP BY 나 ORDER BY를 사용하길 원하면 그 필드를 고정
길이 객체로 만들어야 한다. 이렇게  하는 표준적인 방법은 SUBSTRING  펑션을 사용하는
것이다. 예를 보자:

mysql> select comment from tbl_name order by SUBSTRING(comment,20);

이렇게 하지 않으면 정렬할 때  오직 첫 번째 max_sort_lengths  (기본값=1024)만을 고려된
다.

BLOB 와 TEXT 는 기본값을 가질 수 없으며 또한 언제나 NULL 컬럼일 것이다.

BLOB and  TEXT cannot   have DEFAULT values   and will also  always  be NULL
columns.

5.5 COMMIT-ROLLBACK 없이 어떻게 대치할 수 있을까?
Mysql은 COMMIT-ROLLBACK 을 지원하지 않는다. 문제는 COMMIT-ROLLBACK을 효
과적으로 다루기 위해서는 Mysql에서 현재 사용하는 것과 완전히 다른 테이블 설계가 필요
하다는 것이다. Mysql은 또한 테이블을 자동  클린업하는 추가적인 스레드와 더 많은 디시
크를 사용할 수 있는 기능이 필요하다. 이러한  기능은 현재보다 mysql을 2-4배 느리게 만
든다. Mysql은 대부분의  다른 SQL 데이터베이스보다  훨씬 더 빠르다.  (전형적으로 최소
2-3대 빠름) 이러한 이유는 Mysql에 COMMIT-ROLLBACK이 없기 때문이다.

당분간은 우리는   SQL 서버  언어의  성능을  향상시키는데 더   주력할 것이다.  대부분
COMMIT-ROLLBACK 기능이 정말로 필요한 경우는 드물다. 또한 이렇게 하는 것이 더 좋
은 성능을 낼 수 있다.

일반적으로 트랜잭션이 필요한 루트는 LOCK TABLES를 사용해 코드를 짤  수 있다. 또한
레코드를 업데이트할 때 커서를 사용할 필요가 없다.

우리는 트랜잭션과 커서를 TODO에 넣었지만  우선권이 높은 것은 아니다.  이러한 기능을
수행한다면 CREATE TABLE 의 옵션으로 될 것이다. 이것은 옵션으로 지정한 테이블에서
만 작동하며 그 테이블은 느리게 될 것이라는 것을 의미한다.

우리는   100%   보편적인   데이터보다는   정말로   빠른    데이터베이스가   필요하다.
COMMIT-ROLLBACK 기능을 수행하더라도 속도에 손상이 없다면  우리는 그것을 지원할
것이다. 당분간은 더 중요하게 해야할 일들이  많이 있다. 우리가 어떤 것에 우선권을  두고
있는지는 TODO를 참고하자. 상위 단계의 지원을 받는 고객은 이것을 바꿀 수 있으며 우선
권이 변경될 수도 있다.

현재의 문제는 실제로 ROLLBACK 이다. 롤백없이 LOCK TABLES을 이용하여 여러 종류
의 COMMIT를 사용할 수 있다. 롤백을 지원하기  위해 Mysql은 업데이트가 된 모든 예전
레코드를 저장하고 롤백이 일이났을 때 시작 시점으로 돌아갈 수 있도록 바꾸어야 한다. 예
를 들어 이러한 것은 전혀 어렵지 않다.(현재의 isamlog 는 이런 경우를 위해 사용할 수 있
다) 그러나 ALTER/DROP/CREATE TABLE에서 롤백을 수행하는 것은 무척 어렵다.

롤백 사용을 피하기 위해 다음의 전략을 사용할 수 있다:

1. 접근하기 원하는 모든 테이블에 락을 사용. LOCK TABLES … 
2. 조건 테스트(Test conditions)
3. 모든 것이 제대로 된다면 업데이트를 한다.
4. UNLOCK TABLES

일반적으로 가능한 롤백을 이용해 트랜잭션을 사용하는 것보다는 이러한 방법이 훨씬 더 빠
르다. 그렇지만 항상 사용가능한 것은 아니다. 이러한 방법으로 해결할 수 없는 유일한 상황
은 업데이트중 누군가가 스레드를 죽였을 때이다. 이런 경우 모든 락은 해제가 된다. 그렇지
만 업데이트의 일부는 실행되지 않을 것이다.

물론 단일 오퍼레이션에서 레코드를 업데이트하는 펑션을 사용할 수 있다. 다음의 테크닉을
사용하며 매우 효율적인 애플리케이션을 만들 수 있다:

- 현재 값과 관련되어 있는 필드를 수정
- 실제로 변화가 생겼을때만 필드를 업데이트

예를 들어, 어떤 고객 정보를 업데이트 할 때 오직 바뀐 데이터만 업데이트를 한다. 그리고
For example, when we are doing updates on some customer information, we update only
the customer data that have  changed and test only  that none of the changed  data, or
data that depend on the changed data, have changed compared to the original row.
변화된 데이터의 테스트는 UPDATE 문에서  WHRE 절을 사용하여 할 수  있다. 레코드가
업데이트되지 않았다면 클라이언트에 다음과 같은 메시지를 준다:  “당신이 바꾼 데이터 일
부가 다른 사용자에 의해  바뀌었습니다”. 그러고나서 우리는  윈도우에서 예전의 레코드와
현재의 레코드를 비교하여 보여준다. 그러면  사용자는 어떤 고객 정보  레코드를 사용할지
결정할 수 있다.

이렇게 하면 “컬럼 라킹”과 비슷하다. 그렇지만 실제로는 더 빠르다.  왜냐하면 현재의 값과
관련되어 있는 값의 컬럼만 업데이트하기 때문이다.  이렇나 전형적인 업데이트문은 다음과
비슷할 것이다:

UPDATE tablename SET pay_back=pay_back+’relative change’;

UPDATE customer
  SET
    customer_date=’current_date’,
    address=’new address’,
    phone=’new phone’,
    money_he_owes_us=money_he_owes_us+’new_money’
  WHERE
    customer_id=id AND address=’old address’ AND phone=’old phone’;

지금 보듯이   이렇게 하면  매우  효율적이며  설사 다른   클라이언트가 pay_back   이나
money_he_owes_us 컬럼의 값을 바꾸었을 때라도 제대로 작동한다.

대부분의 경우, 사용자는 테이블에서 유일한 값(identifiers)을 관리하기 위해 롤백과  테이블
락을 사용하고 싶어한다. 이것은  AUTO_INCREMENT 컬럼과 SQL  LAST_INSERT_ID() 
펑션, 또는 mysql_insert_id() 의 C API 펑션을 사용하여 더욱  효율적으로 사용할 수 있다. 
18.4.49 [mysql_insert_id()] 참고.

TcX에서는 언제나 이런 문제를 해결할  수 있기 때문에 결고 low-level  락을 필요로 하지
않는다. 어떤 경우에는 정말로 로우-락이 필요하다. 그렇지만 이런 경우는 극소수이다. 로우
-레벨 락을 원하면 테이블에서 플래그 컬럼을 사용할 수 있다. 다음과 같다:

UPDATE tbl_name SET row_flag=1 WHERE id=ID;

만약 row가 발견되고 row_flag가 원래의  row에서 이미 1이 아니라면  영향을 받은 row의
숫자로서 1일 반환한다.

MySQL returns 1 fro the number of  affected rows if the row was found  and row_flag
wasn’t already 1 in the original row.

6. Mysql 접근 권한 시스템

mysql 은 진보적이지만 비표준적인 보안/권한 시스템을 가지고 있다. 이번 장에서는 이것이
어떻게 작동하는지를 설명하고 있다.

6.1 권한 시스템이란 무엇인가?
Mysql 권한 시스템의 주요 기능은 데이터베이스에서 select, insert, update, delete 권한
을 호스트의 사용자 이름과 관련짓는 것이다.

추가적인 기능에는 익명 사용자  기능과 LOAD DATA INFILE 과 관리자 오퍼레이션과 같은 my
sql만의  특수한 권한을 허용하는 부분이 포함되어 있다.


Mysql에서 인증을 목적으로 사용하는 사용자 이름은 유닉스 사용자 이름(로그인 이름)이나
위도우 사용자 이름고는 전혀 관계가 없다는 것!을 기억하자. 대부분 mysql 클라이언트는 m
ysql 사용자 이름으로 현재의 유닉스 사용자 이름을 사용하여 접속하려 할 것이다. 그렇지
만 이건 오직 편의를 위해서이다. 클라이언트 프로그램은 -u 나 –user 옵션으로 지정한 다
른 이름을 허용한다. 이것은 mysql 사용자 이름에 비밀번호를 설정하지 않으면 데이터베이
스의 보안에 문제가 생길 수 있다는 것을 의미한다. 어떤 이름을 사용하여 서버에 접속하려
고 하는 사람은 각 이름에 비밀번호가 설정되어 있지 않다면 접속에 성공할 것이다.

유닉스 사용자 이름이 일반적으로 8글자로 제한되어 있는 것과 다르게 mysql 사용자 이름은
16글자까지 사용할 수 있다.

mysql 비밀번호는 유닉스의 비밀번호와 아무 관련이 없다. 유닉스 머신에 로그인할 때 사용
하는 비밀번호와 데이터베이스에 접속할 때 사용하는 비밀번호는 전혀 관련이 없다. 또한 m
ysql은 유닉스 로그인 프로세스에서 사용하는 것과 다른 알고리즘으로 비밀번호를 암호화한
다.


6.2 mysql 서버에 접속하기

mysql 클라이언트 프로그램은 일반적으로 연결 패러미터(매개 변수)가 필요하다.: 연결할
호스트, 사용자 이름, 비밀번호. 예를 들어 mysql 클라이언트는 다음과 같이 시작할 수 있
다. (선택 인자는 [ ] 로 닫는다)

shell>; mysql [-h host_name] [-u user_name] [-pyour_pass]


-p와 뒤에 붙은 비밀번호 사이에는 공간이 없다는 것을 기억하자.

-h, -u, -p를 대체할 수 있는 형식으로는 –host=host_name, –user=user_name and –passw
ord=your_pass  이 있다.

mysql은 커맨드 라인에서 연결 매개변수가 빠져있을 때는 기본 값을 사용한다. 기본 호스트
이름은 localhost 이고 기본 사용자 이름은 유닉스 로그인 이름이다.(-p 가 빠져있으면 비
밀번호는 사용하지 않는다) 그래서 만약 유닉스 사용자 이름이 joe 라면 다음의 명령은 동
일하다.:

shell> mysql -h localhost -u joe
shell> mysql -h localhost
shell> mysql -u joe
shell> mysql


다른 mysql 클라이언트도 비슷하게 작동한다.

유닉스 시스템에서 연결을 할 때 사용할 수 있는 기본 값이 있어서 클라이언트 프로그램을
사용할 때마다 명령행에서 옵션을 사용하지 않아도 된다:

ㅇ 홈 디렉토리의 ‘.my.cnf’ 설정 파일의 [client]  섹션에서 연결 변수를 설정할 수 있다.
파일에서 이와 연관된 섹션은 다음과 같다:
[client]
host=host_name
user=user_name
password=your_pass

4.14.4 [option files] 참고.

ㅇ 환경 변수를 사용하여 연결 변수를 지정할 수 있다. 호스트는 MYSQL_HOST 로 지정할 수
있다. Mysql  사용자 이름은 USER, LOGNAME, 또는 LOGIN을 사용할 수 있다. (이러한 값들은
이미 유닉스 로그인 이름으로 설정되어 있을 것이다. 그러므로 바꾸지 않는게 좋다) 비밀번
호는 MYSQL_PWD로 지정할 수 있다.(그렇지만 이것은 안전하지 않다; 다음 섹션을 참고하자)

연결 변수가 여러 가지 방법을 지정되었다면 명령행에서 지정한 값이 설정 파일과 환경 변
수로 설정한 것보다 우선권을 가진다. 또한 설정 파일의 값이 환경 변수보다 우선권을 가진
다.

6. 2. 1 비밀번호의 보안 유지

다른 사용자가 발견할 수 있게 비밀번호를 지정하는 방법은 권하지 않는다. 클라이언트 프
로그램을 실행할 때 비밀번호를 지정하는 방법은 아래와 같으며 각 방법마다 위험도를 같이
설명하였다:

ㅇ 명령행에서 -pyour_pass 또는 –password=your_pass 옵션 사용.  이 방법은 편리하지만
위험한 방법이다. 비밀번호를 시스템 상황 프로그램(ps 등)을 통해 볼 수 있기 때문에 다른
사용자가 명랭행으로 볼 수 있다.(mysql 클라이언트는 일반적으로 초기화되는 동안 명령행
인자를 0으로 덮어씌운다. 그렇지만 값을 볼 수 있는 짧은 틈이 여전히 있다)

ㅇ -p 또는 –password 옵션 사용(비밀번호 값을 지정하지는 않음). 이런 경우 클라이언트
프로그램은 터미널에서 비밀번호를 물어본다:
shell> mysql -u user_name -p
Enter password: ********

클라이언트는 비밀번호를 칠 때 터미널에서 ‘*’  문자를 보여준다. 그러므로 다른 사용자가
비밀번호를 볼 수 없다. 다른 사용자가 볼 수 없으므로 명령행에서 비밀번호를 입력하는 것
보다 훨씬 더 안전하다. 그렇지만 이 방법은 비대화식의 스크립트로 클라이언트 프로그램을
사용하면 적절하지 않다.

ㅇ 설정 파일에 비밀번호 저장. 예를 들어 홈 디렉토리의 ‘.my.cnf’ 파일에서 [client] 섹
션에 비밀번호를 지정할 수 있다.
[client]
password=your_pass

비밀번호를 ‘.my.cnf’ 파일에 저장한다면 그 파일은 그룹이나 다른 사용자가 읽기/쓰기를
할 수 없도록 해야 한다. 파일의 퍼미션이 400 이나 600 인지 확인하자.

4.14.4 [옵션 파일] 참고.

ㅇ 비밀번호를 MYSQL_PWD 환경 변수에 저장할 수 있다. 그렇지만 이 방법은 정말로 위험하
며 사용해서는 안된다. 일부 ps 프로그램은 실행 프로세스의 환경변수를 보여주는 옵션이
있다; MYSQL_PWD에 설정을 하면 다른 사람들이 쉽게 비밀번호를 볼 수 있다. 이런 기능의 p
s가 없는 시스템일지라도 프로세스 환경변수를 검색할 수 있는 방법이 없다고 생각하는 것
은 현명하지 못하다.

이중에서 가장 안전한 방법은 클라이언트 프로그램이 비밀번호를 요구하거나 적절하게 보안
이 된 ‘.my.cnf’ 파일에 비밀번호를 지정하는 것이다.

6.3 mysql에서 제공하는 권한

권한과 관련된 정보는 mysql 데이터베이스의(데이터베이스 이름이 mysql 임) user, db, hos
t, table_priv, columns_priv  테이블에 저장된다. mysql 서버는 시작할 때, 그리고 환경을
지정할 때(6.7 [권한 변경] 참고) 이 테이블의 내용을 읽어들인다.

mysql에서 제공하는 권한을 설정할 때 사용하는 이름은 아래와 같다.테이블의 컬럼 이름은
grant tables의 각 권한 및 권한이 적용되는 context와 연관되어 있다.


Privilege              Column         Context
(권한)          (컬럼)         (환경)
select         Select_priv     tables
insert         Insert_priv     tables
update         Update_priv     tables
delete         Delete_priv     tables
index          Index_priv      tables
alter          Alter_priv      tables
create         Create_priv     databases, tables or indexes
drop            Drop_priv       databases or tables
grant          Grant_priv      databases or tables
reload         Reload_priv     server administration
shutdown       Shutdown_priv   server administration
process        Process_priv    server administration
file            File_priv               file access on server


select, insert, update, delete 권한은 데이터베이스의 테이블에서 레코드에 대한 오퍼레
이션을 할 수 있도록 허용한다.

SELECT 문은 오직 실제로 테이블에서 줄(레코드)를 가져올 때만 select 권한이 필요하다.
서버의 데이터베이스에 접근 권한이 없는 경우라고 하더라도 특정한 SELECT  문은 사용할
수 있다. 예를 들면 간단한 계산을 위해 mysql 클라이언트를 사용할 수 있다:

mysql> SELECT 1+1;
mysql> SELECT PI()*2;

index(인덱스) 권한은 인덱스를 생성하거나 제거할 수 있다.

alter 권한은 ALTER TABLE 을 사용할 수 있도록 한다.

create  와 drop 권한은 새로운 데이터베이스와 테이블을 생성하거나 존재하는 데이터베이
스와 테이블을 제거할 수 있도록 허용한다.

사용자에게 mysql 데이터베이스의 drop 권한을 허용하면, 그 사용자는 mysql 접근권한 정보
가 저장된 데이터베이스를 없앨 수 있다는것!을 명심하자.


grant 권한은 사용자가 가지고 있는 권한을 다른 사용자가 가질 수 있도록 허용한다.

file 권한은 LOAD DATA INFILE and SELECT … INTO OUTFILE  문을 이용하여 서버에 파일을
저장하고 읽을 수 있는 권한을 허용한다. 이러한 권한을 가진 사용자는 mysql 서버가 읽고
쓸 수 있는 파일을 읽고 쓸 수 있는 권한이 허용된다.

나머지 권한들은 관리자 오퍼레이션에 사용되며 mysqladmin 프로그램의 기능을 수행한다.
아래의 테이블은 각 관리자 권한에 따라 사용할 수 있는 mysqladmin 명령을 보여준다:

Privilege              Commands permitted to privilege holders
(권한)          (권한에 따라 허용되는 명령)
reload         reload, refresh, flush-privileges, flush-hosts, flush-logs, flush-tab
les
shutdown       shutdown
process        processlist, kill


reload 명령은 서버가 grant 테이블을 다시 읽어 들인다. refresh 명령은 모든 열린 테이블
을 닫으며 로그 파일을 열고 닫는다. flush-privileges 는 reload 명령과 동의어이다. 다른
flush-* 명령은 refresh 와 비슷한 기능을 수행한다. 그러나 범위에 제한이 있으며 어떤 경
우에는 더 선택할 만하다. 예를 들어 로그 파일만 닫고 다시 열고자 한다면 flush-logs 가
refresh보다 더 나은 선택이다.
(** flush의 옵션으로는 호스트, 로그 파일, 권한 설정, 테이블, status variables 설정 변
수가 있다. SQL 문에서 또는 mysqladmin 유틸리티를 사용하면 된다. **)

shutdown 명령은 서버를 셧다운한다. (** 이거 번역 맞아~~?? **)

processlist 명령은 서버에서 실행되고 있는 스레드에 대한 정보를 보여준다. kill 명령은
서버 스레드를 죽인다. 언제나 자신의 스레드는 보거나 죽일 수 있지만 다른 사용자에 의해
시작된 스레드는 프로세스 권한이 있어야 보거나 죽일 수 있다.

몇가지 권한은 조심스럽게 허용해야 한다:y:

ㅇ grant(허용) 권한은 사용자가 다른 사용자의 권한을 설정할 수 있도록 허용한다. 다른
권한과 grant 권한을 가진 두 사용자는 권한을 결합할 수 있다.
ㅇ file 권한은 서버에서 모든 사람이 읽기 가능한 파일을 읽는데 남용 될 수 있…. SELEC
T  문을 이용해 접근할 수 있는 내용…
The file privilege can be abused to read any world-readable file on the server into a
database table, the contents of which can then be accessed using SELECT.
(** 굳이 권한을 주지 않아도 이용할 수 있는 것은 권한을 주지 않는게 낫다는 말이겠지요
**)
ㅇ shutdown 권한은 다른 사용자에가 완전히 서비스를 사용하지 못하도록 남용될 수 있다.
ㅇ  process 권한은 비밀번호를 설정하고 바꾸는 질의를 포함해 현재 수행하고 있는 질의를
보는데 사용될 수 있다.
ㅇ mysql 데이터베이스에 대한 권한은 비밀번호와 다른 접근 권한 정보를 바꾸는 데 사용될
수 있다. (비밀번호가 암호화되어 저장되었다고 하더라도, 충분한 권한을 가진 악의있는 사
용자는 다른 비밀번호롤 바꿀 수 있다)

mysql 권한 시스템으로 다룰 수  없는 몇가지가 있다:
ㅇ 접근을 거부할 사용자를 명백하게 지정할 수 없다. 왜냐하면 사용자와 연결을 거부하는
것을 완전하게 연관시킬 수 없기 때문이다.
ㅇ 사용자가 테이터베이스에서 테이블을 만들고 지울 수 있는 권한을 가질 수 있지만 데이
터베이스 자체를 만들고 삭제할 수는 없도록 지정할 수 없다.
(** 그러니까 create 와 drop 권한을 주면 데이터베이스 자체에 대해 제어할 수 있지요. 그
안의 테이블만 만들고 지울 수 있도록 하지는 못한다는 말 **)

{{}}
6.4 권한 시스템 작동 방법

mysql 권한 시스템은 모든 사용자가 허용된 것만큼만 할 수 있도록 보증한다. mysql 서버에
연결할 때, 사용자 확인은 연결한 호스트와 사용자가 지정한 사용자 이름에 의해 결정된다.
시스템은 사용자 확인과 지정한 권한에 따라 권한을 허용한다.


mysql은 사용자를 확인하는데 호스트이름과 사용자 이름 둘다 사용한다. 왜냐면 인터넷에서
이름이 같다고 같은 사용자라고 생각할 수는 없기 때문이다. 예를 들어 whitehouse.gov에서
접속하는 사용자 bill 은 microsoft.com에서 접속하는 사용자 bill 과 같은 사람일 필요는
없다. mysql은 때론 같은 이름을 가지고 있더라도 호스트를 이용해 사용자를 구별한다 : wh
itehouse.gov에서 접속하는 bill에게 특정한 권한을 허용할 수 있고 microsoft.com에서 접
속하는 bill에게 다른 권한을 허용할 수 있다.

mysql의 접근 제어는 두가지 단계가 있다:

단계 1: 서버에서 사용자가 연결할 수 있는지 없는지 판단

단계 2 (서버에 사용자가 연결이 허용되었을 경우) : 사용자가 수행하려는 명령에 대해 충
분한 권한이 있는지 각 요청마다 서버에서 판단.예를 들면, 데이터베이스의 테이블에서 sel
ect rows를 할때, 또는 데이터베이스에서 테이블을 제거할 때 서버에서 테이블에 대한 sele
ct 권한이 있는지 데이터베이스에 대한 제거 권한이 있는지 확인을 한다.



서버는 접근 제어의 각 두 단계에서 mysql 데이터베이스의 user, db, host 테이블을 이용한
다.grant 테이블의 필드는 아래와 같다:

Table name     user            db              host
Scope fields   Host            Host            Host
(필드 범위)     User            Db              Db
                Password                User
Privilege fields      Select_priv     Select_priv     Select_priv
(권한 필드)     Insert_priv     Insert_priv     Insert_priv
                Update_priv     Update_priv     Update_priv
                Delete_priv     Delete_priv     Delete_priv
                Index_priv      Index_priv      Index_priv
                Alter_priv      Alter_priv      Alter_priv
                Create_priv     Create_priv     Create_priv
                Drop_priv       Drop_priv       Drop_priv
                Grant_priv      Grant_priv      Grant_priv
                Reload_priv            
                Shutdown_priv          
                Process_priv           
                File_priv              


접권 제어의 두번째 단계를 위해(요청 인증), 요청이 테이블에 관계된 것이라면 추가적으로
tables_priv 와 columns_priv 테이블을 참고한다. 이 테이블의 필드는 다음과 같다:

Table name     tables_priv     columns_priv
Scope fields   Host            Host
                Db              Db
                User            User
                Table_name      Table_name
                                Column_name
Privilege fields      Table_priv      Type
                Column_priv    
Other fields   Timestamp       Timestamp
                Grantor




각 승인(grant) 테이블은 필드 범위와 권한 필드로 구성되어 있다.

필드 범위는 테이블에서 각 엔트리의 범위를 결정한다. 다시 말하면 엔트리가 적용되는 con
text(환경, 배경)이다. 예를 들면, Host 와 User 값이 ‘thomas.loc.gov’ 와 ‘bob’ 인 user
테이블 엔트리는 thomas.loc.gov 호스트에서 bob이 연결을 할때 서버에서 인증을 하는데 사
용된다.비슷하게 Host, User, db 필드값이  ‘thomas.loc.gov’, ‘bob’, ‘reports’ 인 db 테
이블 엔트리는 thomas.loc.gov 호스트에서 bob 이 reports 데이터베이스에 접근할 때 사용
된다. tables_priv 와 columns_priv 테이블은 테이블이나 각 엔트리가 적용될 수 있는 테이
블/컬럼 조합을 가리키는 범위 필드를 포함하고 있다.

접권 체크를 하기 위해, HOst 값 비교는 대소문자를 구별하지 않는다. User, Password, Db,
Table_name 값은 대소문자를 구별한다. mysql 3.22.12 와  이후 버전에서 Column_name 값은
대소문자를 구별하지 않는다. (3.22.11에서는 대소문자 구별함)

권한 필드는 테이블 엔트리에 승인되는 권한을 가리키며 이는 수행할 수 있는 오페레이션이
다. 서버는 사용자의 권한을 완벽하게 설정하기 위해 다양한 승인(grant) 테이블의 정보를
조합한다. 여기에 사용하는 규칙은 6.6 [Request access]를 참고하자.

범위 필드는 문자열이며 다음과 같이 정의되었다; 기본 값은 빈 문자열이다:

Field name     Type   
Host            CHAR(60)       
User            CHAR(16)       
Password                CHAR(16)       
Db              CHAR(64)      (CHAR(60) for the tables_priv and columns_priv tables)



user, db, host 테이블에서 모든 권한 필드는 ENUM(‘N’,'Y’)로 정의되어 있다. — 각각은
‘N’ 나 ‘Y’의 값을 가지며 기본값은 ‘N’ 이다.
(** ENUM 타입은 목록 값중 오직 하나의 값만 가진다.필드 타입 참조 **)

tables_priv 와 columns_priv 테이블에서 권한 필드는 SET 필드로 정의된다:
(** SET 타입은 목록 값중에 0이나 1개 이상의 값을 가진다 **)

Table name     Field name     Possible set elements
tables_priv     Table_priv      ‘Select’, ‘Insert’, ‘Update’,
                                ‘Delete’, ‘Create’, ‘Drop’, ‘Grant’,
                                ‘References’, ‘Index’, ‘Alter’
tables_priv     Column_priv     ‘Select’, ‘Insert’, ‘Update’,
                                ‘References’
columns_priv    Type            ‘Select’, ‘Insert’, ‘Update’,
                                ‘References’

간단하게 말해서 서버는 승인(grant) 테이블을 다음과 같이 사용한다:

ㅇ user 테이블의 scope(범위) 필드는 들어오는 연결에 대해 허용할 것인지 거부할 것인지
를 결정한다. 허용된 연결에 대하여, 권한 필드는 사용자의 전체적인 (superuser) 권한을
가리킨다.

ㅇ db 와 host 테이블은 함께 사용된다:
        – db 테이블의 범위 필드는 어떤 호스트에서 어떤 데이터베이스에 대해 어떤 사용
자가 접근할 수 있는지 결정한다. 권한 필드는 어떤 오퍼레이션이 허용되었는지를 결정한
다.
        – host 테이블은 db 테이블의 엔트리를 여러개의 호스트에 적용하려고 할 때 db 테
이블의 확장을 위해 사용한다.예를 들어, 사용자가 현재 네트웍의 여러 호스트에서 데이터
베이스를 사용할 수 있도록 하려면,사용자의 “db” 테이블 엔트리에 Host 값을 비워두고, “h
ost” 테이블에 각 호스트의 엔트리를 넣으면 된다.이러한 절차는 6,6 [Request access]에
자세하게 나와 있다.

ㅇ tables_priv 와 columns_priv 테이블은 db 테이블과 비슷하다. 그렇지만 더 세부적으로
지정할 수 있다: 이 테이블들은 데이터베이스 단계에서 더 나아가 테이블과 컬럼 단계에 적
용할 수 있다.

관리 권한(reload, shutdown,기타..)은 오직 user 테이블에서만 지정을 할 수 있다는 것을
기억하자! 왜냐면 관리자 오퍼레이션은 서버 자체에 대한 오퍼레이션이며 특정한 데이터베
이스를 지정하는 것이 아니다. 그러므로 이러한 권한은 다른 승인(grant) 테이블에 있을 필
요가 없다.실제로, 오직 user 테이블만이 관리자 오퍼레이션을 수행할 수 있는지 없는지를
결정할 때 참고가 된다.

파일(file) 권한도 마찬가지로 user 테이블에서만 지정한다.위와 같은 관리 권한은 아니다.
그렇지만 서버 호스트에서 파일을 읽거나 쓸 수 있는 권한은 접근하고 있는 데이터베이스와
무관한 것이다.

mysqld 서버는 시작할 때 승인(grant) 테이블을 한번 읽는다. 승인 테이블을 변경하고 효과
를 발휘하려면 6.7 [Privilege changes]를 참고하자.

승인 테이블의 내용을 수정했을 때 원하는대로 권한이 설정되었는지 확인하는 것은 좋은 생
각이다. 유용한 진단 프로그램은 mysqlaccess 스크립트로서 Yves CArlier 가 mysql distrib
ution 으로 제공하고 있다. 어떻게 작동하고 있는지 확인하기 위해 mysqlaccess 에 –help
옵션을 주어 실행해보자. 물론 6.11 [Access denied] 와 6.12 [Security]를 참고하자.


mysqlaccess는 오직 user, db, host 테이블만 점검한다. 테이블이나 컬럼 단계의 권한까지
는 점검하지 않는다는 것을 기억하자.

6.5 접근 제어, 단계 1 : 연결 확인(인증)

mysql 서버에 접속하려고 할 때 서버는 사용자 확인과 비밀번호를 통해 접속을 허용하거나
거부한다. 사용자 확인이 안되면 서버는 접속을 완전히 거부한다. 사용자 확인이 되면 서버
는 연결을 받아들이고 2번째 단계로 들어가며 요청을 기다린다.

사용자 확인은 두가지 정보에 기반하고 있다:

ㅇ 접속하는 호스트
ㅇ mysql 사용자 이름

사용자 확인은 user 테이블의 세가지 범위 필드(Host, User, Password)를 사용하여 수행된
다. 서버는 user 테이블 엔트리의 호스트이름과 사용자 이름이 맞으며, 비밀번호가 정확할
때만 접속을 받아들인다.

아래와 같이 user 테이블의 범위 필드값을 지정할 수 있다:

ㅇ Host 값은 호스트 이름이나 IP 숫자 또는 로컬 호스트를 가리키는 ‘localhost’ 가 될 것
이다.
ㅇ Host 필드에서 ‘%’ 와 ‘_’ 의 와일드카드 문자를 사용할 수 있다.
ㅇ ‘%’의 Host 값은 모든 호스트 이름을 나타낸다. 공백의 호스트 값은 ‘%’와 같다. 특정한
호스트에 대한 이러한 값은 당신의 서버에 연결할 수 있다는 것을 참고하자.
ㅇ 와일드카드 문자는 User 필드에는 허용되지 않는다. 그렇지만 모든 유저에 해당하는 공
백으로 둘 수 있다. 연결을 하려는 목록에 공백 사용자 이름이 있다면 클라이언트에서 실제
로 지정한 이름 대신에 그 사용자는 익명 사용자, 이름이 없는 사용자로서 간주된다.
ㅇ Password 필드는 공백으로 될 수 있다.이것은 아무런 비밀번호나 사용할 수 있다는 것을
의미하는 것은 아니며 사용자는 비밀번호를 지정하지 않고 연결을 해야 한다는 의미이다.

아래의 테이블은 연결 요청에 적용하는 “user” 테이블 목록의 Host, User 값이 어떻게 조합
되는지를 보여주는 예제이다:

호스트값/사용자 값 : 목록에 해당하는 연결
‘thomas.loc.gov’/'fred’ : thomas.loc.gov 에서 연결하는 fred
‘thomas.loc.gov’/” : thomas.loc.gov 에서 연결하는 모든 사용자
‘%’/'fred’ : 모든 호스트에서 연결하는 fred
‘%’/” : 모든 호스트에서 연결하는 모든 사용자
‘%.loc.gov’/'fred’ : loc.gov 도메인의 모든 호스트에서 연결하는 fred
‘x.y.%’/'fred’ : x.y.net, x.y.com, x.y.edu 등에서 접속하는 fred (이것은 아마도 유용하
지 않을 것이다)
’144.155.166.177′/’fred’ : 144.155.166.177의 IP 주소에서 접속하는 fred
’144.155.166.%’/'fred’ : 144.155.166 클래스 C 서브넷의 모든 호스트에서 접속하는 fred


Host 필드에서 IP에 와일드 카드를 사용할 수 있기 때문에(예를 들어 ’144.155.166.%’ 는
서브넷의 모든 호스트에 적용된다) 144.155.166.somewhere 와 같은 호스트 이름을 이용하여
부당하게 이용할 가능성이 생길 수 있다. 이러한 것을 막기 위해 mysql은 숫자와 도트(.)으
로 시작하는 호스트이름은 허용하지 않는다. 1.2.foo.com 과 같은 호스트라면 이러한 호스
트이름은 승인(grant) 테이블의 Host 컬럼과 매치되지 않는다. IP 숫자만이 IP 와일드 카드
값과 매치시킬 수 있다.

만약 한개 이상의 user table 목록이 있다면 서버는 어떻게 user table을 선택할까? 이런
경우에는 user table의 정렬 순서에 따라 해결을 하며 , 정열은 서버가 시작할때 수행이 된
다. user table이 다음과 같다고 가정해보자:


+———–+———-+-
| Host      | User     | …
+———–+———-+-
| %         | root     | …
| %         | jeffrey  | …
| localhost | root     | …
| localhost |          | …
+———–+———-+-



서버가 테이블을 읽을 때, 먼저 특정하게 지정된 값이 있는 호스트부터 목록을 정열한다.
(Host 컬럼에서 ‘%’는 “모든 호스트”를 의미하여 최소한도로 지정하는 것이다) 목록에서 호
스트값이 같으면 먼저 특정하게 지정된 사용자가 있는 것부터 정열한다.(공백으로 되어 있
는 User 값은 “모든 사용자”를 의미하여 최소한도로 지정하는 것이다.) 이렇게 하면 정열된
user 테이블은 다음과 같다:



+———–+———-+-
| Host      | User     | …
+———–+———-+-
| localhost | root     | …
| localhost |          | …
| %         | jeffrey  | …
| %         | root     | …
+———–+———-+-


정열된 순서에 따라 매칭 알고리즘이 적용되며 먼저 매칭되는 것을 사용한다. localhost에
서 jeffrey가 연결을 하려할때, Host 컬럼에서 ‘localhost’ 목록이 먼저 매칭된다. 물론 사
용자 이름이 공백인 목록은 연결하는 호스트네임과 사용자 이름에 매칭된다. (‘%’/'jeffrey
‘ 목록 또한 매칭이 된다. 그러나 테이블에서 처음으로 매칭되는 것은 아니다.)


다른 예제가 있다. user 테이블이 다음과 같다고 가정해보자:

+—————-+———-+-
| Host           | User     | …
+—————-+———-+-
| %              | jeffrey  | …
| thomas.loc.gov |          | …
+—————-+———-+-


정열된 테이블은 다음과 같다:

+—————-+———-+-
| Host           | User     | …
+—————-+———-+-
| thomas.loc.gov |          | …
| %              | jeffrey  | …
+—————-+———-+-

첫번째로 thomas.loc.gov에서 jeffrey가 연결하는 것이 매칭되며, whitehouse.gov 에서 jef
frey가 연결하는 거은 두번째로 매칭이 된다.

서버에 연결할 때 문제가 생기면, user 테이블을 출력하여 어떤 것이 먼저 매칭되는지 직접
정열을 하면 된다.


6.6 접근 제어, 2단계 : 요청 인증

{{}}연결되었다면 서버는 2단계로 들어간다. 연결이 성사되었을 때 각 요구에 대해 사용자가 수
행하려는 연산의 유형에 기반하여 서버는 사용자가 충분한 권한을 가지고 있는지 점검한다.
여기서 승인 테이블의 권한 필드가 작동한다. 권한은 user, db, host, table_priv, columns
_priv 테이블의 정보를 사용한다. GRANT 와 REVOKE 명령을 이용하여 권한 테이블을 다룰 수
있다. 7.25 [GRANT] 참고. (이전에 보았던 각 권한 테이블의 필드 목록을 참고하는 것이 도
움이 될 것이다; 6.4[Privilege] 참고.)

user 테이블의 승인 권한은 사용자에게 전체적인 기반을 제공하며 현재의 데이터가 어떤 것
인지와는 상관이 없다. 예를 들어, user 테이블에서 사용자에게 delete 권한을 승인했다면
서버 호스트에서 어떤 데이터베이스의 레코드라도 삭제할 수 있다! 다르게 말해서 user 테
이블 권한은 슈퍼유저 권한이며, 슈퍼유저(서버나 데이터베이스 관리자 등)에게만 user 테
이블에 대한 권한을 승인하는 것이 좋다. 다른 사용자에게는 user 테이블에서 권한을 ‘N’로
설정하고, db와 host 테이블을 사용하여 특정 데이터베이스에 기반한 권한승인을 하는게 좋
다.

db 와 host 테이블은 특정 데이터베이스의 권한을 승인한다. 각 테이블의 Host 와 Db 필드
에서 와일드카드 문자 ‘%’ 와 ‘_’ 를 사용할 수 있으며 값이 공백이면 필드 범위(scope fie
lds)에서 모든 값을 허용한다. ‘%’ Host 값은 “모든 호스트”를 의미한다. db 테이블에서 Ho
st 값이 공백이면 “host 테이블에서 더 자세한 정보를 문의하라”는 의미이다. A ‘%’ or bla
nk Db value in the host table means or “any database.” (** or의 뜻이 무엇인지 모르겠
네요. host 테이블에서 Db 의 값이 ‘%’ 또는 공백이면 “모든 데이터베이스”를 의미한다는
말 같은데요 **) User 값이 공백이면 익명 사용자로 간주된다.

서버가 시작할 때 db 와 host 테이블을 읽고 정열을 한다.(동시에 user 테이블을 읽는다.)
db 테이블은 Host, Db, User 순으로 필드 범위를 정열하며 host 테이블은 Host, Db 순으로
필드 범위를 정열한다. user 테이블과 같이 특정하게 지정되어 있는 값이 먼저 정열되고 최
소한도로 지정된 값이 나중에 정열된다. 서버에서 매칭되는 목록을 찾을때, 가장 먼저 발견
한 것을 사용한다.

tables_priv 와 columns_priv 테이블은 특정한 테이블과 컬럼에 관련된 권한을 승인한다.d
b와 host 테이블의 Host 필드와 같이 와일드카드를 Host 필드에서 사용할 수 있다. 그렇지
만 Db, Table_name, Column_name 필드에서는 와일드카드나 공백값을 사용할 수 없다.

Host 테이블에서만 와일드카드를 사용할 수 있지만 tables_priv 와 columns_priv 테이블은
db 테이블과 비슷하게 정열이 되며 정열은 간단하다.

요청 인증 과정은 아래에서 설명한다. 접근-점검 소스 코드에 친숙하다면, 여기서 설명하는
것은 코드에서 사용된 알고리즘과는 약간 다르다는 것을 알 수 있다.여기서의 설명은 코드
가 실제로 작동하는 방식과 동일하다. 단지 설명을 간단하게 하는데서 차이가 있는 것이다.

관리자 요청에 대해서(shutdown, reload 등) 서버는 단지 user 테이블만 체크를 한다. 왜냐
면 user 테이블에서만 관리자 권한을 지정하기 때문이다. 목록에서 요청된 연산을 허용하면
접근이 허용되며 아닌 경우에는 접근이 거부된다.예를 들어, mysqladmin shutdown을 실행하
고자 하는데 user 테이블 목록에서는 사용자에게 shutdown 권한을 승인하지 않으면, db나 h
ost 테이블을 체크하지 않더라도 접근이 거부된다. (이러한 테이블에는 Shutdown_priv 컬럼
이 없기 때문에 이렇게 할 필요도 없다)

데이터베이스와 관련된 요청에 대해(insert, update 등) 서버는 먼저 user 테이블 목록에서
사용자의 전체(슈퍼유저) 권한을 점검한다. 목록에서 요청한 연산을 허용하면 접근이 승인
된다.

user 테이블에서 전체적인 권한이 불충분하면, 서버는 db 와 host 테이블을 점검하여 데이
터베이스에 관련된 권한을 결정한다:

1. 서버는 db 테이블에서 매칭되는 Host, Db, User 필드를 찾는다. 연결하려는 사용자의 호
스트 이름과 Mysql 사용자 이름이 Host 와 User에 매칭되다. 사용자가 접근하기 원하는 데
이터베이스는 Db 필드에 매칭된다. 적합한 Host 와 User 목록이 없으면 접근은 거부된다.

2. 매칭되는 db 테이블 목록이 있고 Host 필드가 공백이 아니면, 목록은 사용자의 데이터베
이스 관련 권한을 정의한다.


3. 매칭되는 db 테이블 목록의 Host 필드가 공백이면, host 테이블에서 어떤 호스트가 데이
터베이스에 접근할 수 있는지 판단한다는 것을 의미한다. 이런 경우, 더 자세한 정보를 위
해 host 테이블에서 매칭되는 Host 와 Db 필드를 찾는다. host 테이블에 매칭되는 목록이
없으면 접근은 거부된다. 매칭되는 목록이 있으면 사용자의 데이터베이스 관련 권한은 db
와 host 테이블 목록에서 권한을 intersection 하여 결정된다.(** insertection은 교집합을
생각하면 되지요. and 조건 **) 다시 말해서, db와 host 테이블 둘 다 ‘Y’로 되어있을 때
권한이 설정된다.이러한 방법으로 db 테이블에서 일반적인 권한을 승인할 수 있으며, 그러
고나서 host 테이블 목록을 사용해 host를 기반으로 하여 선택적으로 권한을 제한할 수 있
다.)

db 와 host 테이블 목록을 이용해 데이터베이스와 관련된 권한 승인을 결정한 후, 서버는
이러한 정보를 user 테이블에서 승인한 전체적인 권한에 추가한다. 그 결과가 요청한 연산
을 허용하면 접근이 허용된다. 다른 방법으로, 서버는 tables_priv 와 columns_priv 테이블
에서 사용자의 테이블과 컬럼 권한을 점검하고 사용자의 권한에 추가한다. 그 결과에 따라
접근이 허용되거나 거부된다.

왜 서버에서 전체적인 사용자 엔트리 권한에 데이터베이스, 테이블, 컬럼에 관련된 권한을
추가하는지가 명확하지 않다…. 이런 경우 사용자 권한은 초기에 요청된 연산에 대하여 불
충분하다… (It may not be apparent why the server adds the database-, table- and col
umn-specific privileges to the global user entry privileges for those cases in which
the user privileges are initially found to be insufficient for the requested operatio
n.) 요청은 한가지 유형 이상의 권한이 필요하기 때문이다. 예를 들어, INSERT … SELECT
문을 수행할 때 insert 와 select 권한 둘 다 필요하다. 사용자의 권한은 user 테이블에서
한가지 권한을 승인하고 db 테이블 엔트리에서 다른 권한을 승인할 것이다. 이런 경우, 사
용자는 이러한 요청을 수행하기 위해 필요한 권한을 가지고 있다. 그렇지만 서버는 자체적
으로 다른 테이블에 대해서는 …..(In this case, you have the necessary privileges to
perform the request, but the server cannot tell that from either table by itself;) ;
두 엔트리에 의해 승인된 권한이 조합되어야 한다.

host 테이블은 “안전한” 서버 목록을 유지하는데 사용할 수 있다. TcX에서는, host 테이블
에는 지역 네트웍의 모든 시스템이 포함되어 있다. 여기서는 모든 권한이 허용된다.

안전하지 않는 호스트를 가리키기 위해 host 테이블을 사용할 수 있다. 안전하다고 생각되
지 않는 공개 지역에 위치한 public.your.domain 시스템이 있다고 가정해보자. 사용자는 사
용자 네트웍의 모든 호스트에 접근할 수 있으며, host 테이블 엔트리가 다음과 같은 시스템
만 제외한다 :

+——————–+—-+-
| Host               | Db | …
+——————–+—-+-
| public.your.domain | %  | … (all privileges set to ‘N’)
| %.your.domain      | %  | … (all privileges set to ‘Y’)
+——————–+—-+-

당연히 접근 권한이 원하는대로 되어 있는지 언제나 승인 테이블에서 목록을 테스팅해야 한
다. (예를 들어 mysqlaccess 를 사용)



6.7 권한 변경시 적용 방법


mysqld 가 시작할 때, 모든 승인 테이블 내용이 메모리로 올라가고 이때부터 유효하게 된
다.

GRANT, REVOKE, SET PASSWORD 를 이용해 승인 테이블에 변경을 하면 바로 서버에서 인식을
한다.

권한 테이블을 직접 변경했다면(INSERT, UPDATE 등을 사용하여), 서버에서 승인 테이블을
재가동하도록 하기 위해 FLUSH PRIVIEGES 문이나 mysqladmin flush-privileges 를 실행해야
한다.그렇게 하지 않으면 서버를 다시 시작하기 전까지 변경된 권한이 적용되지 않는다.

서버에서 권한 테이블이 변경되었다는 것을 감지했을 때, 이미 존재하던 클라이언트 연결은
다음과 같이 영향을 받는다:

1. 테이블과 컬럼 권한 변경은 클라이언트의 다음 요청부터 적용된다.
2. 데이터베이스 권한 변경은 다음의 USE db_name 명령부터 적용된다.
3. 전체적인 권한과 비밀번호 변경은 클라이언트가 다음에 연결할 때부터 적용된다.
{{}}

6.8 초기 mysql 권한설정

mysql을 설치하고 나서, mysql_install_db 스크립트를 실행해서 초기 접근 권한을 설정해야
한다. 4.7.1 [Quick install] 참고. mysql_install_db 스크립트는 mysqld 서버를 시작하고,
다음과 같이 승인 테이블의 권한을 초기화한다:

- mysql root 사용자는 슈퍼유저이며 모든 것을 할 수 있다. 로컬 호스트에서만 연결할 수
있다.
주의 : 처음에 root 비밀번호는 비어있다. 그래서 누구나 비밀번호없이 root로 연결할 수있
고 모든 권한을 승인받는다.

- 익명 사용자는 ‘test’ 나 ‘test_’ 로 시작하는 데이터베이스에 대한 모든 권한을 승인받
는다. 모든 사용자가 로컬 호스트에서 연결할 수 있으며 익명 사용자로 간주된다.

- 다른 권한은 거부된다. 예를 들어 일반 사용자는 mysqladmin shutdown 이나 mysqladmin p
rocesslist 를 사용할 수 없다.


설치했을 때 초기 권한이 폭넓게  설정되어 있기 때문에 가장 먼저 mysql root 사용자의 비
밀번호를 설정해야 한다. 다음과 같이 설정하면 된다. (PASSWORD() 함수를 이용해 비밀번호
를 설정해야 한다!):

shell> mysql -u root mysql
mysql> UPDATE user SET Password=PASSWORD(‘new_password’)
           WHERE user=’root’;
mysql> FLUSH PRIVILEGES;

or

shell> mysqladmin -u root password new_password
(** PASSWORD() 라는 함수를 사용하지 않아도 되므로 편리함. 또한 SQL문에서 grant 명령을
이용해 설정할 수도 있지요 **)

첫번째 방법을 사용하면 직접 user 테이블의 비밀번호를 업데이트한다. 이경우 서버가 다시
승인 테이블을 읽도록 해야 한다.(FLUSH PRIVILEGES 사용). 왜냐하면 다른 방법으로는 변경
사항을 알릴 수 없기 때문이다.

(** 승인 테이블을 다시 읽지 않아서 이전에 설정했던 비밀번호가 제대로 안되는 경우가 있
을 것입니다. 꼭 기억하고 있어야해요 **)

root 비밀번호가 설정되었으면 서버에 root로 접속할때마다 비밀번호를 명시해야 한다.

추가로 셋업을 하거나 테스트할 때는 비밀번호를 설정할 필요가 없기 때문에 root 비밀번호
를 빈값으로 남겨두고 싶을 것이다. 그렇지만 실제 작업을 하기 전에는 반드시 비밀번호를
설정했는지 확인해야 한다.

기본권한을 어떻게 설정하는지 mysql_install_db 스크립트를 살펴보자. 다른 사용자에게 권
한을 어떻게 설정할지 이것을 기본으로 사용할 수 있다.

위에서 설명한 것과 다르게 초기 권한을 설정하기 원하면, mysql_install_db 스크립트를 실
행하기 전에 수정하면 된다.

완전하게 승인 테이블을 다시 만들기 위해 mysql 데이터베이스를 포함하는 디렉토리의 ‘*IS
M’ 과 ‘*.ISD’ 파일을 제거해야 한다. (이 디렉토리는 database 디렉토리에서 ‘mysq”이라
는 이름이 붙어있다. mysqld –help 해서 database 디렉토리의 목록을 볼 수 있다.) 원하는
대로 권한을 수정한 후 mysql_install_db 스크립트를 실행하자.


6.9 mysql에 새로운 사용자 권한 추가하기

두가지 방법으로 사용자를 추가할 수 있다 : GRANT 문 사용 또는 mysql 승인 테이블 직접
조작. GRANT 문을 사용하는 것이 더 선호되는 방법이다.

아래의 예제는 새로운 사용자를 설정하기 위해 어떻게 mysql 클라이언트를 사용하는지 보여
준다. 이 예제는 이전에 설명했던것과 같이 기본값에 따라 권한을 설정하는 것으로 가정한
다. 이것은 설정을 바꾸기 위해 mysqld가 실행되고 있는 같은 시스템에 있어야 한다는 것을
말한다. (**초기값은 localhost에서만 접속 가능하므로**) 또한 mysql root 사용자로 접속
해야 하고 root 사용자는 mysql 데이터베이스에 대한 insert 권한과 reload 관리자 권한이
있어야 한다. root 사용자의 비밀번호를 바꾸었으면, 아래와 같이 mysql 명령행 상태에서
비밀번호를 명시해야 한다.

GRANT 문을 이용해 새로운 사용자를 추가할 수 있다:

shell> mysql –user=root mysql
mysql> GRANT ALL PRIVILEGES ON *.* TO monty@localhost
           IDENTIFIED BY ‘something’ WITH GRANT OPTION;
mysql> GRANT ALL PRIVILEGES ON *.* TO monty@”%”
           IDENTIFIED BY ‘something’ WITH GRANT OPTION;
mysql> GRANT RELOAD,PROCESS ON *.* TO admin@localhost;
mysql> GRANT USAGE ON *.* TO dummy@localhost;

위 GRANT 문에서는 세 명의 사용자를 설정한다:

monty : 어느 곳에서든 서버에 연결할 수 있는 완전한 슈퍼유저이지만 비밀번호를 사용해야
한다. 우리는 monty@localhost 와 monty@”%”를 사용한 GRANT 문에 대해서 반드시 논의를 해
야 한다. localhost 목록을 추가하지 않으면, mysql_install_db 에 의해 생성된 localhost
의 익명 사용자 목록(등록?)이 로컬 호스트에서 접속할때 우선권을 갖는다. 왜냐하면 지정
된 Host 필드 값이 있으며 정열 순서에서 먼저 오기 때문이다. (** 승인 테이블의 정열 순
서가 특정한 Host를 지정한 것부터 시작하는 것을 기억하자.

admin : 비밀번호 없이 localhost에서 접속할 수 있으며 reload와 process 관리자 권한을
승인받은 사용자. 이경우 사용자가 mysqladmin processlist 뿐만 아니라 mysqladmin reloa
d, mysqladmin refresh, mysqladmin flush-* 명령을 실행할 수 있다.데이터베이스와 관련된
권한은 승인되지 않았다. 이것은 추가적인 GRANT 문을 사용해 나중에 승인할 수 있다.

dummy : 비밀번호없이 연결할 수 있지만 오직 localhost에서만 연결 가능한 사용자. 권한
유형(privilege type)이 USAGE 이기 때문에 전체적인 권한이 ‘N’로 설정되어 있다. USAGE
는 아무런 권한도 설정하지 않는다. 나중에 데이터베이스와 관련된 권한을 승인할 수 있다.

또한 동일한 사용자 접근 정보를 INSERT 문을 통해 직접 추가할 수 있으며 이경우에는 서버
가 승인 테이블을 다시 읽도록 알려주어야 한다.(**FLUSH PRIVILEGES 사용**)

shell> mysql –user=root mysql
mysql> INSERT INTO user VALUES(‘localhost’,'monty’,PASSWORD(‘something’),
                ‘Y’,'Y’,'Y’,'Y’,'Y’,'Y’,'Y’,'Y’,'Y’,'Y’,'Y’,'Y’,'Y’,'Y’)
mysql> INSERT INTO user VALUES(‘%’,'monty’,PASSWORD(‘something’),
                ‘Y’,'Y’,'Y’,'Y’,'Y’,'Y’,'Y’,'Y’,'Y’,'Y’,'Y’,'Y’,'Y’,'Y’)
mysql> INSERT INTO user SET Host=’localhost’,User=’admin’,
                 Reload_priv=’Y', Process_priv=’Y';
mysql> INSERT INTO user (Host,User,Password)
                        VALUES(‘localhost’,'dummy’,”);
mysql> FLUSH PRIVILEGES;

mysql 버전에 따라 위에서 ‘Y’ 값이 다를 수 있다는 것을 기억하자. 3.22.11 버전 이후에서
사용할 수 있는 확장된 INSERT 문은 여기서 admin 사용자에게 사용되었다.

슈퍼유저를 설정하기 위해 권한필드를 ‘Y’로 한 user 테이블 목록만 만들면 된다는 것을 기
억하자. db 나 host 테이블 목록은 필요없다. (** 관리자 권한은 db나 host 테이블과는 전
혀 관련이 없다. db는 접속할 수 있는 데이터베이스에 대해 상세하게 설정하고 host 테이블
은 db테이블을 좀 더 정교하게 설정하기 위해 필요한 것이다. 관리자 권한은 오직 user 테
이블만 관련되어있다 **)

마지막 INSERT 문(dummy 사용자)에서는 user 테이블의 권한 컬럼이 명확하게 설정되지 않았
다. 왜냐면 이 컬럼의 기본값은 ‘N’로 되어 있기 때문이다.

다음의 예제에서는 custom 이라는 사용자를 추가한다. custom은 localhost, server.domain,
whitehouse.gov에서 접속할 수 있다. localhost에서는 bankaccount 데이터베이스에만 접속
할 수 있으며 whitehouse.gov에서는 expenses 데이터베이스에, 모든 세 호스트상에서는 cus
tomer 데이터베이스에 접속하길 원한다. 모든 세 호스트상에서 stupid라는 비밀번호를 사용
하길 원한다.

GRANT 문을 이용 이러한 사용자 권한을 설정하기 위해 다음의 명령을 실행하자:

shell> mysql –user=root mysql
mysql> GRANT SELECT,INSERT,UPDATE,DELETE,CREATE,DROP
           ON bankaccount.*
           TO custom@localhost
           IDENTIFIED BY ‘stupid’;
mysql> GRANT SELECT,INSERT,UPDATE,DELETE,CREATE,DROP
           ON expenses.*
           TO custom@whitehouse.gov
           IDENTIFIED BY ‘stupid’;
mysql> GRANT SELECT,INSERT,UPDATE,DELETE,CREATE,DROP
           ON customer.*
           TO custom@’%’
           IDENTIFIED BY ‘stupid’;

승인 테이블을 직접 수정해 사용자 권한을 설정하려면 다음의 명령을 사용하자. (마지막에
FLUSH PRIVILEGES 를 사용해야 한다는 것을 기억하자):

shell> mysql –user=root mysql
mysql> INSERT INTO user (Host,User,Password)
       VALUES(‘localhost’,'custom’,PASSWORD(‘stupid’));
mysql> INSERT INTO user (Host,User,Password)
       VALUES(‘server.domain’,'custom’,PASSWORD(‘stupid’));
mysql> INSERT INTO user (Host,User,Password)
       VALUES(‘whitehouse.gov’,'custom’,PASSWORD(‘stupid’));
mysql> INSERT INTO db
       (Host,Db,User,Select_priv,Insert_priv,Update_priv,Delete_priv,
        Create_priv,Drop_priv)
       VALUES
       (‘localhost’,'bankaccount’,'custom’,'Y’,'Y’,'Y’,'Y’,'Y’,'Y’);
mysql> INSERT INTO db
       (Host,Db,User,Select_priv,Insert_priv,Update_priv,Delete_priv,
        Create_priv,Drop_priv)
       VALUES
       (‘whitehouse.gov’,'expenses’,'custom’,'Y’,'Y’,'Y’,'Y’,'Y’,'Y’);
mysql> INSERT INTO db
       (Host,Db,User,Select_priv,Insert_priv,Update_priv,Delete_priv,
        Create_priv,Drop_priv)
       VALUES(‘%’,'customer’,'custom’,'Y’,'Y’,'Y’,'Y’,'Y’,'Y’);
mysql> FLUSH PRIVILEGES;
~~~~~~~~~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~~~~~~~~~~~~~

처음의 세가지 INSERT 문은 custom 사용자가 비밀번호를 사용하여 다양한 호스트에서 접속
할 수 있도록 user 테이블 목록을 추가한다. 그렇지만 그에게 어떠한 퍼미션도 승인하지 않
는다. (모든 권한은 기본값으로 ‘N’ 이다) 다음의 세가지 INSERT 문은 적절한 호스트에서
접속을 할 때, custom 에게 bankaccount, expenses, customer 데이터베이스에 대한 권한을
승인하는 db 테이블 목록을 추가한다. 일반적으로 승인 테이블을 직접 수정하였으면, 변경
된 권한을 적용하기 위해 서버가 승인 테이블을 다시 읽도록 해 주어야 한다.

특정한 사용자가 특정한 도메인의 시스템에서 접속할 수 있도록 설정하고자 한다면, 다음과
같이 GRANT 문을 설정할 수 있다:

mysql> GRANT …
           ON *.*
           TO myusername@”%.mydomainname.com”
           IDENTIFIED BY ‘mypassword’;

승인 테이블을 직접 수정하려면 다음과 같이 한다:

mysql> INSERT INTO user VALUES (‘%.mydomainname.com’, ‘myusername’,
           PASSWORD(‘mypassword’),…);
mysql> FLUSH PRIVILEGES;
~~~~~~~~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~~~~~~~~~~~~

승인 테이블을 다루기 위해 xmysqladmin, mysql_webadmin, xmysql 프로그램을 사용할 수 있
다. http://www.mysql.com/Contrib 에서 이러한 유틸리티를 찾을 수 있다.


6.10 비밀번호 설정 방법

앞의 예제는 중요한 원칙을 보여준다 : INSERT 나 UPDATE 문에서 공백이 아닌 비밀번호를
저장할 때 반드시 암호화하기 위해 PASSWORD() 함수를 사용해야 한다!! user 테이블은 비밀
번호를 플레인텍스트(**일반 텍스트 파일**)가 아니라 암호화된 형태로 저장하기 때문이다.
이러한 사실을 잊어버리면 다음과 같이 비밀번호를 설정하려고 할 것이다:

shell> mysql -u root mysql
mysql> INSERT INTO user (Host,User,Password)
       VALUES(‘%’,'jeffrey’,'bLa81m0′);
mysql> FLUSH PRIVILEGES;

플레인텍스트 값 ‘bLa81m0′ 은 user 테이블에 비밀번호로 저장이 된다.jeffrey라는 사용자
가 이 비밀번호를 사용해 서버에 연결하려고 할 때 mysql 클라이언트를 이 비밀번호를 암호
화해서 그 결과를 서버로 보낸다. 서버는 암호화된 비밀번호(‘bLa81m0′이 아니다)를 user
테이블의 비밀번호(플레인텍스트 ‘bLa81m0′ 값이다)와 비교한다. 비교는 실패하고 서버는
연결을 거부한다:

shell> mysql -u jeffrey -pbLa81m0 test
Access denied

비밀번호는 user 테이블에 입력될 때 반드시 암호화되어야 하기 때문에, INSERT 문은 다음
과 같이 사용해야 한다:

mysql> INSERT INTO user (Host,User,Password)
       VALUES(‘%’,'jeffrey’,PASSWORD(‘bLa81m0′));

또한 SET PASSWORD 문을 사용할 때도 PASSWORD() 함수를 사용해야 한다:

mysql> SET PASSWORD FOR jeffrey@”%” = PASSWORD(‘bLa81m0′);

참고 : PASSWORD() 함수는 비밀번호 암호화를 수행한다. 그렇지만 유닉스에서 비밀번호를
암호화하는 방법과는 다르다. 유닉스 비밀번호와 mysql 비밀번호가 동일할 때 PASSWORD()
가 유닉스 비밀번호 파일(** /etc/passwd 파일 **)에 암호화되어 저장된 값과 같다고 생각
하면 안 된다.

GRANT … IDENTIFIED BY 문이나 mysqladmin password 명령을 사용해 비밀번호를 설정하면
PASSWORD() 함수는 필요없다. 둘다 비밀번호를 암호화해서 저장한다:

mysql> GRANT USAGE ON *.* TO jeffrey@”%” IDENTIFIED BY ‘bLa81m0′;
shell> mysqladmin -u jeffrey password bLa81m0

(** 당근, GRANT 문이나 mysqladmin password 명령을 사용하는게 편하겠지요? mysql의 암호
화 알고리즘이 유닉스와 다르듯 유닉스 계정과 mysql의 사용자는 전혀 다르다는 것도 다시
한번 기억하고 있어야 합니다.**)



6.11 접근 거부 에러가 나는 이유

mysql 서버에 연결하려 할 때 접근 거부 에러가 나면, 아래에서 설명하는 것에 따라 해결
방법을 찾을 수 있다:

- 초기 승인 테이블 내용을 설정하기 위해 mysql을 설치한 후 mysql_install_db 스크립트를
실행하였는가? 실행하지 않았다면 스크립트를 실행하자. 6.8 [Default privileges] 참고.
다음 명령을 이용해 초기 권한을 시험해 볼 수 있다:

        shell> mysql -u root test

에러없이 서버에 접속할 수 있을 것이다. mysql 데이터베이스 디렉토리에 ‘user.ISD’ 파일
이 있는지 확인해보아야 한다. (일반적으로 ‘mysql 설치 디렉토리/var/mysql/user.IDS’ 이
다)

- 설치를 새로하고 난후 , 서버에 연결하고 사용자와 접근 권한을 설정해야 한다:

        shell> mysql -u root mysql

초기에 mysql root 사용자만 비밀번호가 없기 때문에 서버에 연결할 수 있다. 보안문제가
있기 때문에, 다른 mysql 사용자를 설정하기 전에 먼저 root의 비밀번호를 설정해야 한다.
root로 접속하려하는데 다음의 에러가 났다고 가정하자:

        Access denied for user: ‘@unknown’ to database mysql

이것은 user 테이블에 User 컬럼 = root 라는 목록이 없고, mysqld가 사용자 클라이언트의
호스트이름을 해석할 수 없다는 것을 의미한다. 이런 경우 –skip-grant-tables 옵션을 이
용해 서버를 다시 시작해야 하고 ‘/etc/hosts’ 를 편집하거나 ‘\windows\hosts’ 파일에 사
용자 호스트 목록을 추가해야 한다.

- 3.22.11 이전 버전에서 3.22.11이나 이후 버전으로 업데이트했다면, mysql_fix_privilege
_tables 스크립트를 실행했는가? 하지 않았다면 실행하자. mysql 3.22.11에서 GRANT 문 기
능이 가능해지면서 승인 테이블 구조가 바뀌었다.

- (INSERT 나 UPDATE 문을 사용해) 승인 테이블을 직접 고쳤고 변화가 아직 반영되지 않은
것으로 보이면, FLUSH PRIVILEGES 문을 사용하거나 mysqladmin flush-privileges 명령을 사
용해 서버가 승인 테이블을 다시 읽도록 해야 한다는 것을 기억하자.그렇지 않으면 서버가
재시작하기 전까지는 변화된 것이 반영되지 않는다. root 비밀번호를 설정하고 나서 권한을
flush 하기까지는 비밀번호를 명시할 필요가 없다. 왜냐면 서버는 아직 비밀번호를 바꾸었
는지 모르기 때문이다.

- 세션 중간에 권한이 변경된 것으로 보이면 슈퍼유저가 바꾸었을 것이다. 승인 테이블을
재시작하는 것은 새로운 클라이언트 접속에 영향을 미치지만 이미 존재하고 있던 연결은 6.
7 [Privileges changes]에서 설명한대로 영향을 미친다.

- 시험하기 위해, mysqld 대몬에  –skip-grant-tables 옵션을 주어 시작하자. 그러고나서
mysql 승인 테이블을 변경할 수 있고 변경된것이 원하는대로 작동하는지를 체크하는 mysqla
ccess 스크립트를 사용할 수 있다. 원하는대로 수정이 되었으면 mysqld 서버가 새로운 승인
테이블로 시작할 있도록 mysq1admin flush-priveleges 를 실행한다.
주의 : 승인테이블을 재로딩하는 것은 –skip-grant-tables 옵션을 무효화한다. 이를 통해
서버를 다운시키고 다시 재시작하지 않고도 승인 테이블을 시작할 수 있다.

- 펄, Python, ODBC 프로그램에서 접근하는데 문제가 있다면, mysql -u user_name db_name 
또는 mysql -u user_name -pyour_pass db_name 으로 서버에 접속을 시도해보자. (-p 와 비
밀번호사이에는 공백이 없다는 것을 기억하자. 또한 –password=your_pass 형태로도 사용할
수 있다) mysql 클라이언트로 접속이 되면 프로그램에 문제가 있는 것이며 접근 권한에는
문제가 없다.

- 비밀번호가 제대로 작동하지 않으면, INSERT, UPDATE, SET PASSWORD 문에서 비밀번호를
설정하면서 PASSWORD() 함수를 반드시 사용해야 한다는 것을 기억하자. PASSWORD() 함수는
GRANT … INDENTIFIED BY 문이나 mysqladmin password 명령을 사용했다면 불필요하다. 6.1
0 [Passwords] 참고.

- localhost 는 지역 호스트 이름과 같은 말이다. 또한 호스트를 명백하게 설정하지 않은
경우 클라이언트에서 연결하려는 호스트의 기본값이다. 그러나 MIT-pthreads를 사용하는 시
스템에서는 localhost로의 연결이 제대로 작동하지 않는다. (localhost 연결은 유닉스 소켓
을 통해 만들어진다. 그렇지만 MIT-pthreads에서는 유닉스 소켓을 지원하지 않는다.) 이와
같은 시스템에서 문제를 피하려면, 서버에 호스트 이름을 명확하게 말해주기 위해 –host
옵션을 사용해야 한다. 그러면 mysqld 서버에 TCP/IP 연결을 만든다. 이경우, 서버 호스트
의 user 테이블 목록에 실제 호스트이름이 있어야 한다. (서버와 동일한 호스트에서 클라이
언트 프로그램을 실행한다고 하더라도 마찬가지이다.)

- mysql -u user_name db_name 으로 데이터베이스에 접속하려 할 때 접근 거부 에러가 나
면, user 테이블에 문제가 있을 것이다. mysql -u root mysql 를 실행하여 점검하고 다음의
SQL 문을 사용하자:

        mysql> SELECT * FROM user;

여기서 사용자의 호스트이름과 mysql 사용자 이름과 맞는 Host 와 User 컬럼의 목록이 포함
되어 있어야 한다.

- Access denied 에러 메시지는 접속하려는 사용자와 호스트 이름, 그리고 비밀번호를 사용
했는지 여부를 보여줄 것이다. 일반적으로 user 테이블에 에러 메시지에서 보여준 호스트
이름과 사용자 이름과 정확하게 맞는 목록을 가지고 있어야 한다.


- 다른 시스템에서 mysql 서버에 접속할 때 다음의 에러 메시지가 나오면, user 테이블에
연결을 하려고 하는 호스트 이름이 없다는 것을 말한다:

        Host … is not allowed to connect to this MySQL server

(서버 호스트에서!) 명령행 유틸리티인 mysql을 사용하여 user 테이블에 연결하고자 하는
사용자/호스트 이름을 추가하여 해결할 수 있다. mysql 3.22 를 사용하고 있지 않고 연결하
고자 하는 시스템의 IP 숫자나 호스트 이름을 모른다면, user 테이블에 Host 컬럼 값으로
‘%’ 목록을 입력하고 서버 시스템에서 –log 옵션을 사용해 mysqld 를 재시작하자. 클라이
언트 시스템에서 연결을 시도한 후 mysql 로그에는 어떻게 실제로 연결을 했는지에 대한 정
보가 들어있다. (그러고나서 ‘%’를 로그에 나온 실제 호스트 이름으로 바꾼다. 그렇지 ?邦

[펌] LINUX(Red Hat 9)에서 Oracle 9i Release 2 설치 방법

0

Installation of Oracle 9i Release 2 (9.2.0.4.0) on REDHAT 9 LINUX



1. Linux 개요


Linux는 1991년 리누스 토발즈가 0.01을 만들고(실제로 0.01은 발표가 되지 않음), 0.02를 뉴스그룹에 포팅한 이래로, 큰 변화와 발전을 거듭해왔다. 최근 발표되어 배포판에 적용되기 시작한 Kernel 2.6.7은 지원이 제대로 되지 않아 문제가 되었던 하이퍼스레딩 테크놀로지(Hyperthreading Technology : CPU의 유휴 자원부분에 대한 활용 방법의 하나로 1개의 CPU에서 마치 2개의 CPU를 가동하는 것과 같은 효과를 내는 기술) 부분이 완벽하게 지원되는 등 그 적용범위가 날로 넓어지고 있다.
또한 이미 64bit CPU에 대한 지원은 윈도우 64bit 버전이 개발되기 전보다도 더 빨리 적용되었고 또한 그만큼 빨리 개선이 되고 있다.
물론 일부 어플리케이션이 잘 적용이 되지 않는다는 불만의 목소리도 있으나 이는 Kernel의 개발속도와 이에 따른 Linux의 버전업을 어플리케이션이 쫓아가지 못하는 것으로 Linux 문제라고 하기에는 무리가 있다. 뒤에서도 설명하겠지만 Linux 버전의 Oracle의 경우, 각 배포판을 만드는 회사의 개선점을 제대로 쫓아가지 못하는 것 때문에 오히려 낮은 버전에서 설치할 경우가 더 잘되는 경우가 있다. 실제로도, Oracle 8i의 경우, REDHAT 6.2에 최적화되어 있어 그 이상의 버전에 설치하려면 glibc package를 downgrade해야 했고, Oracle 8i 자체에 포함된 Java Runtime Environment에도 문제가 있어 JDK를 별도로 설치해야 하는 등 문제가 많았다.(이에 대해서는 지난 번에 배포한 설치문서를 참고하기 바람) Oracle 9i의 경우에는 REDHAT 7.3에서 개발된 것이다.
하지만, 저렴한 비용과 일부 Enterprise 상용버전의 경우 개발사의 전폭적인 지원을 통해 많은 부분을 해결할 수 있다는 것은 큰 장점이라 할 수 있을 것이다.
현재 Linux는 REDHAT 이외에도 Novell과 통합한 SuSE Linux, Mandrake, Debian, Slackware 등 여러가지 버전이 있다. 하지만 REDHAT의 경우, 배포판 Linux의 개발을 중단하고(이에 따른 무상 지원도 2004년 4월 30일자로 완전 중단함), 대신에 REDHAT에서 100% 지원하고 있는 Fedora Linux Project를 통해 개선된 부분을 자사의 상용 Enterprise 버전에 도입하는 방식으로 개발방향을 바꿨다. 현재 Fedora 프로젝트를 통해서 나온 버전은 core 2가 ISO 포맷으로 CD 또는 DVD 방식의 이미지 파일을 제공하고 있으며 Fedora Linux Project의 rpm은 지속적으로 Update 되고 있다.
 
2. REDHAT 9의 특성 및 Oracle 설치를 위한 REDHAT 9 설치 지침


(1) REDHAT 9의 특성
Redhat의 전체적인 특징으로 바로 Redhat 시스템에 최적화된 어플리케이션을 제공하고 있다는 것이다. 바로 RPM이다. RPM은 Redhat Package Manager로 일일이 컴파일하여 설치해야 할 것을 Package 형태로 곧바로 설치만 하면 사용가능하게끔 만든 파일이다.(이는 solaris에서 pkgadd 명령으로 설치하는 것과 경로명이 약간 차이나는 것과 설치명령과 옵션이 다르다는 것 이외에는 매우 유사한 과정을 거쳐 설치가 된다)
이 RPM은 국내에서 제작하고 있는 REDHAT 계열의 Linux에서도 마찬가지로 적용되고 있는 것으로, 한컴Linux나 와우Linux에서도 RPM을 사용하여 설치를 하고 있고, SuSE Linux에서도 확장자만 다를 뿐 유사한 방식에 의해 Package를 설치, 업그레이드, 제거를 하고 있다.


(2) RPM으로 어플리케이션의 추가, 업그레이드, 삭제
- 추가 : rpm -ivh *.rpm
- 업그레이드 : rpm -Uvh *.rpm
- 제거 : rpm -e *.rpm


이것이 기본이지만, 다양한 옵션이 있다. rpm의 옵션은 다양하므로, 처음에는 rpm –help를 하는 습관을 들인다.
rpm 추가는 업그레이드 옵션으로 하는 것을 권장한다. 만약 동일한 Package가 있을 경우 자동으로 업그레이드 해준다.
rpm을 제거할 경우 다른 것에 의존성이 있는 경우 –nodeps 옵션을 추가하여 다음과 같이 하면 된다.
rpm -e –nodeps *.rpm
rpm은 하나씩 설치하거나 제거할 수도 있지만, 여러 개를 한꺼번에 설치할 수도 있다. 의존성 관계에 있는 rpm의 경우 반드시 한꺼번에 설치해야 한다.


(3) REDHAT에서 중요하게 바뀐 것
REDHAT에서 가장 중요하게 바뀐 것이라면 바로 POSIX와 관련된 스레드 라이브러리(thread library)의 변경이다. 이 때문에 Oracle 어플리케이션 설치가 고도의 삽질이 되는 것이다. POSIX란 Portable Operating System Interface의 약자로써 운영체제의 공통적인 규약을 규정하고 있는 표준이다. C 프로그래밍 시에 규약이 제각각이라면 개발자가 소스코드를 이해하기 어려울 뿐더러 다른 시스템의 이식이 거의 불가능할 것이다. 이를 위해 공통된 규약을 마련하였는데 그것이 바로 POSIX인 것이다.
REDHAT 9부터는 Native POSIX Thread Library(NPTL)라는 것을 적용하기 시작했는데, Linux에서 POSIX thread의 수행능력을 강화한 것이다. 하지만 바로 이 NPTL 때문에 Oracle 9i가 제대로 설치되지 않는 문제점이 있다. 실제로 Oracle에서는 REDHAT 9에 대해서는 certification을 주지 않았다.


(4) 참고 : Enterprise 버전의 보장성
배포판을 만드는 회사는 별도의 상용 Linux를 판매한다. REDHAT의 경우, 미화 1500달러에서 1달러 모자른 1499달러에 Advanced Server가 판매된다. 같은 AS 버전도 프리미엄 에디션은 2499달러에 판매된다.
우리가 Linux에 Oracle DBMS를 포팅한다고 할 때, 중요한 문제가 있다. 바로 책임의 범위이다. 우리가 대개 하드웨어와 OS로 인한 문제가 발생할 때, 배포판의 경우에는 바로 시스템관리자에게 전적으로 책임이 있다. 따라서, OS 구입에 별도의 비용이 들지 않는다는 이유 때문에 배포판 Linux를 선택하는 경우, 시스템관리자가 유닉스/Linux에 대한 기초적인 수준만이라도 사전지식이 필요하다. Linux는 완성된 시스템이 아니고, 항상 개선이 이루어지는 오픈 소스이기 때문에 버그 등으로 인해 서버가동이 중단될 경우, 이에 대한 책임은 전적으로 시스템관리자가 져야 하는 것이다.
따라서 항구적인 DB를 구축해야 할 경우, 수요자가 Linux를 선택한다면 이런 경우는 상용 Linux를 적극적으로 고려해볼 필요가 있다.
상용 Linux의 경우, 개발회사에서 전적으로 책임을 지기 때문에, 설치자가 애초부터 설치를 잘못하지 않은 한, OS로 인한 문제에 대해 관리자가 책임이 어느 정도 경감된다.(모든 시스템이 다 그렇지만 일차적으로 시스템 관리자의 시스템 관리가 항상적으로 이루어져 함은 상식이다)
따라서 항상성을 보장해야 하는 시스템에서 특히 어떤 방식으로든 백업/복구 시스템이 구축되어 있다면 상용 Enterprise Linux 시스템도 상당히 고려해볼 만한 이점이 있다.
 
(5) REDHAT 9의 설치 지침
- Linux를 처음 설치한다면 전체설치를 한다
- Linux를 처음 대하는 사람이라면 전체설치를 권한다. 이전 8i 버전에서는 KDE 환경에서만 설치가 되는 문제점이 있었는데(GNOME에서는 잘 안되고 그나마도 한컴 Linux 2.2에서만 설치가 되었다. 한컴 Linux 2.2는 한글화된 KDE를 X Window 환경으로 사용함) 테스트 결과 GNOME, KDE 관계없이 설치가 진행된다. REDHAT의 경우는 오히려 KDE보다 GNOME에서 설치가 잘 진행되었다. KDE의 경우 이에 의존성이 있는 Package들이 문제를 많이 일으켰다.
- 반드시 Package Update를 수행한다. 업데이트를 해야만 설치가 가능하다.
- 또한 반드시 최초 설치 후 모든 설치 Package들에 대해 반드시 Update를 해준다. kernel의 경우에는 Update가 꼭 필요한 것은 아니지만, 해당 Package들의 Update가 끝나면 나중에라도 Kernel Update를 해주기를 권장한다. Kernel은 시스템 기동과 입출력, CPU 제어를 담당하는 가장 기본적인 Package이므로 이에 대한 개선은 항시적으로 이루어지고 있다.
- REDHAT의 경우 update 관련 Package는 REDHATLinux의 Update 관리자에서 Update 되지 않으므로 수동으로 업그레이드 해줘야 한다.
- 다음과 같이 실행한다.
- rpm -Uvh up2date-3.1.23.2-1.i386.rpm up2date-gnome-3.1.23.2-1.i386.rpm
- rpm은 위와 같이 동시에 설치가능하며 특히 중복성이 있는 Package의 경우 필히 동시에 2개의 Package를 설치해야 한다.
- 이렇게 한 다음 Update 관리자를 통해 Red Hat Network에 접속해서 Update하는 것을 권장한다. 시간이 좀 걸리긴 하지만 일일이 Update 파일을 받아서 하는 것에 비하면 훨씬 편리하다.
- 참고 : Red Hat Linux Customization Guide 중 5장 Package Management 부분을 참조할 것.


(6) REDHAT 9 설치를 위한 하드웨어 사양
- 하드웨어는 CPU 개수가 많고, 클럭 속도가 높고, 물리적 메모리와 하드디스크의 공간이 크면 당연히 좋겠지만 그렇지 않을 경우 최소한 다음의 조건은 충족시켜야 한다.
- RAM 512MB 이상, Oracle DBMS 설치공간 최소 2.5GB(custom), 3.5GB(typical)
- REDHAT 9을 설치하기 위한 사양 :
  CPU:
     – Minimum: Pentium-class
     – Recommended for text-mode: 200 MHz Pentium-class or better
     – Recommended for graphical: 400 MHz Pentium II or better


  Hard Disk Space (NOTE: Additional space will be required for user data):
     – Custom Installation (minimum): 475MB
     – Server (minimum): 850MB
     – Personal Desktop: 1.7GB
     – Workstation: 2.1GB
     – Custom Installation (everything): 5.0GB


  Memory:
     – Minimum for text-mode: 64MB
     – Minimum for graphical: 128MB
     – Recommended for graphical: 192MB


3. Oracle 설치 전 준비사항


(1) user 생성
- Oracle 설치에 필요한 user를 생성한다. 다른 UNIX 시스템과 마찬가지로 dba 그룹과 oracle user를 생성한다.
- Linux에서는 Korn Shell(ksh)과 C Shell(csh)의 장점만을 모은 Borne Again Shell(bash)을 사용한다.
- bash는 형식은 Borne Shell 또는 Korn Shell과 비슷하다. 변수 선언시  Korn Shell과 완전히 동일한 형식으로 선언하지만, 실제 기능에 있어서는 C Shell의 장점도 포함된 까닭(C shell의 명령어 집합이 사용가능)에 Linux에서 가장 많이 쓰이는 쉘이다.


(2) Linux에서 user생성
- Linux에서는 user 생성이 다른 상용 유닉스 서버처럼 관리 프로그램을 사용해서 생성이 잘 되지 않는다. 대신 전통적으로 사용되는 명령어 groupadd, useradd 명령을 사용하여 생성하도록 한다. 유닉스에도 이 명령어가 있지만 그냥 관리 프로그램(Solaris의 경우 admintool, AIX의 경우 smit, 또는 smitty groups, smitty users를 사용하면 되고 그 외의 경우에는 예전에 별도로 배포한 유닉스 명령어 비교표를 참고하도록 하라.
- 다음과 같은 방법으로 생성한다.
groupadd [-g gid [-o]] [-r] [-f] group
ex) groupadd -g 101 dba
-g는 group ID(GID)를 지정하는 것으로 101번을 dba 그룹으로 지정하는 것이다.
이미 101번이 사용되고 있다면 에러가 날 것이고 그럴 때는 다른 넘버를 지정해준다. GID를 자동으로 받을 때는 -g 옵션을 빼고 groupadd dba 해도 된다.
- user의 경우에는 다음과 같은 방법으로 생성한다.
방법1 : useradd [-u uid(사용자 아이디) [-o]] [-g 그룹명][-G 그룹,...] [-d 홈디렉토리][-s 쉘][-c 적요사항][-m [-k template]] [-f 비활성화] [-e 만기] [-p passwd] [-M] [-n] [-r] name
방법2 : useradd -D [-g 그룹명][-b 초기디렉토리][-s 쉘] [-f 비활성화] [-e 만기]
ex) useradd -g 101 -u 1001 -d /oracle -s /bin/bash -m oracle
대개 이런 식으로 user를 생성한다. 여기서 중요한 옵션은 GID 지정 옵션인 -g, user ID(UID) 옵션인 -u, 기본 directory 지정 옵션인 -d, shell 지정 옵션인 -s, 그리고 디렉토리가 존재하지 않을 때 생성(make)하라는 옵션인 -m이다. 그리고 맨 뒤에 생성할 user명을 적어준다.
- 참고로 검색엔진과 검색 데몬을 소유하는 user인 kolasii는 쉘 지정 시 보통 C Shell을 사용하므로 일반 상용 UNIX와 동일하게 설정해주면 된다.
- 참고 : 다른 POSIX를 따르는 다른 시스템도 마찬가지이지만 대개 /etc 디렉토리에 보면 기본 쉘 파일이 있다. Borne Shell, Korn Shell, Borne Again Shell 등은 /etc 디렉토리의 profile을 기본 파일로 사용하며, C Shell의 경우에는 csh.cshrc와 csh.login을 사용한다. C Shell의 경우 .cshrc가 우선권이 있고 여기에 모든 환경변수를 지정하면 된다. 일반 적으로 .login 파일에까지 환경변수를 지정할 필요가 없다.


(3) 필수 Package 확인
- Oracle 인스톨 시 반드시 설치되어야만 하는 Package 목록이다. 되도록 최신 버전의 Package를 설치하도록 한다. 하나라도 누락되면 아예 설치화면 자체가 실행되지 않을 수도 있다.
- 반드시 있어야 하는 Package 목록과 버전(최소한 이 버전 이상은 되어야 한다)
- 다음의 명령어로 확인한다 :
rpm -qa gcc cpp glibc-devel binutils compat-gcc compat-libgccj compat-libgccj-devel nss_db-compat compat-libstdc++ glibc-kernheaders
 
- 설치되어야 하는 Package 버전(표 형태로 되어 있어 생략)


(4) Kernel Setting
- 이 부분은 매우 중요한 것으로 서버 성능을 어떻게 조절하느냐의 문제이다. Kernel은 다시 컴파일할 수도 있고 컴파일하면서 다양한 옵션을 줄 수가 있다. 또한 이를 통해서 구태여 사용하지 않는 서비스는 아예 부팅할 때부터 뺄 수가 있다. 이를 통해서 메모리를 절약할 수 있고 부팅시간을 줄임으로서 시스템의 속도개선을 꾀할 수 있다. 여기서는 다루는 범위를 벗어나므로 별도 서적을 통해서 직접 습득하기 바란다.
- Oracle에서 제시하는 설치(정확히는 Oracle 인스턴스 생성)에 필요한 Kernel 파라미터의 설정값은 다음과 같다 :
SEMMNI 100
SEMMNS 256
SEMMSL 100
SEMOPM 100
SEMVMX 32767
SHMMAX 2147483648
One-half the size of your system’s physical memory. Check your system for additional restrictions.
SHMMIN 1
SHMMNI 100
SHMSEG 4096
- Linux는 Kernel 파라미터를 보수적으로 잡기 때문에 이를 늘려줘야 할 필요가 있다. 따라서 하드웨어의 specification을 잘 살펴보고, 이에 맞게 적절한 값을 설정하도록 한다.
- SHMMAX가 기본값인 33554432로 잡혀 있으면 인스턴스 생성 시 다음의 에러를 내게 된다 :
ORA-27123 : unable to attach to shared memory segment
(참고로 SHMMAX는 SGA의 잠재적인 한계가 될 수 있다)
- SHMMAX의 최대값은 (4-1)GB까지 설정할 수 있다. 대개 물리적 주소 확장없이 구축된 32bit Linux 시스템은 3GB의 사용자 공간과 1GB의 Kernel 스페이스로 구분된다
- /etc/sysctl.conf에 다음을 추가로 설정 :
kernel.shmmax = 2147483648
kernel.shmmni = 4096
kernel.shmall = 2097152
kernel.sem = 250 3200 100 128
fs.file-max = 65536


net.ipv4.ip_local_port_range = 1024 65000
- /etc/security/limits.conf에도 다음을 추가 설정 :
oracle soft nofile 65536
oracle hard nofile 65536
oracle soft nproc 16384
oracle hard nproc 16384
- 이렇게 한 다음 리부팅하면 적용된다.
- 이렇게 하지 않으려면 다음과 같은 방법을 사용해도 된다.
# echo 250 32000 100 128 > /proc/sys/kernel/shm
# echo 2147483648 > /proc/sys/kernel/shmmax
# echo 4096 > /proc/sys/kernel/shmmni
# echo 2097152 > /proc/sys/kernel/shmall
# echo 65536 > /proc/sys/fs/file-max
# echo 1024 65000 > /proc/sys/net/ipv4/ip_local_port_range
- 모든 shared memory의 세팅은 다음의 명령어로 확인한다 :
ipcs -lms
- 다음과 같은 결과를 보여준다 :
—— Shared Memory Limits ——–
max number of segments = 4096
max seg size (kbytes) = 32768
max total shared memory (kbytes) = 8388608
min seg size (bytes) = 1
—— Semaphore Limits ——–
max number of arrays = 128
max semaphores per array = 250
max semaphores system wide = 32000
max ops per semop call = 32
semaphore max value = 32767


(5) Swap Space Setting
- 인스턴스 생성 시 최소 512MB의 메모리 공간을 필요로 한다.
- 대개 Linux에서 기본 세팅은 최소 400MB 이상, 메모리의 두 배 이상을 스왑으로 설정할 것을 권장하나, Oracle에서는 1GB 이상, 메모리의 양과 동일한 크기로 잡을 것을 요구함.
- 물리적 메모리를 확인하기 위해서는 :
grep MemTotal /proc/meminfo
- 스왑 공간을 확인하기 위해서는 :
cat /proc/swaps
- 임시 스왑공간을 확보하기 위해서는 :
su – root
dd if=/dev/zero of=tmpswap bs=1k count=90000
chmod 600 tmpswap
mkswap tmpswap
swapon tmpswap
- 스왑공간을 제거하기 위해서는 :
su – root
swapoff tmpswap
rm tmpswap


(6) /tmp 공간 설정
- 최소 400MB 이상의 공간이 필요함
- tmp 디렉토리가 충분하지 않을 경우, 다음과 같이 설정한다 :
su – root
mkdir /<AnotherFilesystem>/tmp
chown -R root:root /<AnotherFilesystem>/tmp
chmod 1777 /<AnotherFilesystem>
export TEMP=/<AnotherFilesystem> # used by Oracle
export TMPDIR=/<AnotherFilesystem> # used by Linux Programs
- 제거할 때는 다음과 같이 한다 :
su – root
rmdir /<AnotherFilessystem>/tmp
unset TEMP
unset TMPDIR


4. Oracle 설치


(1) Oracle 쉘 환경 설정
- 반드시 다음의 표준 쉘을 사용하도록 한다. 이는 Oracle 8i부터 10g까지 범용으로 적용될 수 있는 환경변수 정의이다. Oracle 10g의 경우 ORACLE_BASE 변수를 지정하면 경고메시지를 보여주나 그냥 넘어가면 된다. 무시하고 넘어가도 상관없다.(계정보안에 따른 것으로 보임)


# Get the aliases and functions
if [ -f ~/.bashrc ]; then
        . ~/.bashrc
fi


# User specific environment and startup programs


PATH=$PATH:$HOME/bin


export PATH
unset USERNAME


umask 022
export LANG=C


# Set the LD_ASSUME_KERNEL environment variable only for Red Hat 9 and for Red Hat Enterprise #Linux Advanced Server 3 (RHEL AS 3) !!
# Use the “Linuxthreads with floating stacks” implementation instead of NPTL:
# Use old Linuxthreads with floating stacks instead of the new Native POSIX Thread Library (NPTL)
export LD_ASSUME_KERNEL=2.4.1
export THREADS_FLAG=native


#not used in oracle 9i, but used in oracle 8i because of bugs of jre :
#export JRE_LOCATION=/usr/local/java


# Oracle Environment
export ORACLE_BASE=/oracle
export ORACLE_HOME=$ORACLE_BASE
export ORACLE_SID=K2UP
export ORACLE_OWNER=oracle
#export ORACLE_TERM=vt100
export ORACLE_TERM=xterm
export NLS_DATE_FORMAT=”YYYY/MM/DD”
export ORACLE_DOC=$ORACLE_BASE/doc
export TMPDIR=$ORACLE_BASE/tmp


# export TNS_ADMIN= Set if sqlnet.ora, tnsnames.ora, etc. are in $ORACLE_HOME/network/admin
export TNS_ADMIN=$ORACLE_HOME/network/admin


export ORA_NLS33=$ORACLE_HOME/ocommon/nls/admin/data


# change this NLS settings to suit your country :
export NLS_LANG=KOREAN_KOREA.KO16MSWIN949


# Set shell search paths
export PATH=$PATH:.:$ORACLE_HOME/bin:/usr/local/java/bin:/usr/bin:/usr/openwin/bin:/usr/ucb:/etc:/sbin:/usr/ccs/bin:/usr/bin/X11:/usr/xpg4/bin:/bin:/usr/local/bin


#only AIX :
export LIBPATH=$ORACLE_HOME/lib:$ORACLE_HOME/lib32:$ORACLE_HOME/lib64:/usr/lib:/lib:/usr/ccs/lib


#all UNIX/LINUX except of AIX
export LD_LIBRARY_PATH=$ORACLE_HOME/lib:$ORACLE_HOME/lib32:$ORACLE_HOME/lib64:/usr/lib:/lib:/usr/ccs/lib:/usr/local/lib


#not used :
#export CLASSPATH=$ORACLE_HOME/jre:$ORACLE_HOME/JRE:$ORACLE_HOME/jre/1.3.1:$ORACLE_HOME/jre/1.3.1/bin:$ORACLE_HOME/jlib:$ORACLE_HOME/rdbms/jlib:$ORACLE_HOME/network/jlib:/usr/local/jdk/lib/classes.zip


#export DISPLAY=192.168.1.242:0.0
export DISPLAY=hostname:0.0
export LINK_CNTRL=L_PTHREADS_D7


- 처음 user를 생성하면 .bash_profile의 형식은 다음과 같다 :
# Get the aliases and functions
if [ -f ~/.bashrc ]; then
        . ~/.bashrc
fi
  
# User specific environment and startup programs
  
PATH=$PATH:$HOME/bin
  
export PATH
unset USERNAME


- 여기에 다음과 같이 추가로 변수를 지정한다 :
- umask 022 : 쉘의 권한을 지정. 디렉토리를 생성하게 되면 755로 지정된다.
- LANG=C : 문자세트를 UNIX 기본 세트로 지정. 다른 나라의 로칼(locale)을 제대로 인식못하고 자바 윈도우가 종료될 수 있기 때문에 무조건 C로 잡을 것. 이렇게 하면 모든 설치메시지는 영문으로 표기된다.
- LD_ASSUME_KERNEL=2.4.1 : 이는 REDHAT 9의 Native POSIX Thread Library(NPTL)로 인해서 발생하는 문제를 해결하기 위해서 강제로 Linuxthreads with Floating Stacks 방식을 사용하기 위한 것이다. 이렇게 하면 Kernel을 2.4.1로 인식하고 예전 방식의 Linuxthread Library를 사용할 수 있다. Floating Stack 방식마저도 제외하겠다면 그 때는 2.2.5로 설정하면 된다.
- export THREADS_FLAG=native : THREADS_FLAG는 Solaris에서 사용하는 Multithreading 옵션으로 green(디폴트값)과 native를 선택할 수 있다. native를 명시적으로 지정해야만 한다.
- JRE_LOCATION : Oracle 9i Release2에서 더 이상 JRE의 버그는 없다. 예전 8i에서는 blackdown.org에서 제대로 동작하는 자바실행환경을 별도로 받아 설치하고 Oracle 설치파일의 파라미터 파일도 직접 수정해야만 설치가 되었지만 이제는 그럴 필요가 없다. 주석처리하고 사용한다.
- ORACLE_TERM=xterm : vt100 대신 xterm으로 지정
- CLASSPATH는 JAVA의 라이브러리를 지정할 때 쓰는 변수로, 8i에서 JRE가 제대로 작동하지 않는 이유 때문에 반드시 지정을 해야만 했다. 하지만 9i Release 2에서는 JRE가 제대로 작동하므로 별도 지정이 필요없다. 지정을 하라고 하지만 지정하지 않아도 잘 설치된다.
- DISPLAY : 유닉스 명령어 hostname으로 나오는 결과를 적어준다. IP가 2개 이상 부여되어 있거나 방화벽을 통해 IP가 mapping되어 있는 경우 등으로 인해 IP를 직접 적시하는 것이 애매할 경우 hostname으로 하면 된다. 무슨 원칙이 있는 것은 아니지만 hostname을 적어주도록 한다.


(2) 설치 과정
- xhost + hostname 또는 xhost 127.0.0.1 또는 xhost + host IP : Oracle 인스톨러가 X window 상에서 실행될 수 있도록 하는 명령(root user에서 실행). hostname이나 localhost로 하는 것을 권장한다.
- su – oracle
- ./runInstaller : 인스톨러를 실행한다.
- 참고 1 : CDROM으로 설치할 경우, CDROM 마운트는 반드시 root user에서 /mnt/cdrom 등에 마운트한다. 그리고 절대로 oracle user로 CDROM을 마운트해서는 안된다. 이렇게 하게 되면 oracle user에서 CDROM을 바꿔줄 때 oracle user 소유의 모든 process를 kill해야 하고 이렇게 되면 더 이상 Oracle을 설치할 수가 없게 되므로 반드시 root user가 CDROM을 마운트하도록 한다.
- 참고 2 : 이것은 CDROM이 자동으로 마운트되는 솔라리스의 경우에도 동일하게 적용된다. Oracle user에서 설치하고 있는 창은 그대로 놓아두고 별도 창을 열어서 root user에서 eject 명령을 내리는 것과 같다.
- 인스톨을 시작하게 되면 다음과 같은 팝업 창이 뜬다.



(3) 최초 설치 안내 창
 
- 설치를 시작하게 되면 Oracle Universal Installer 2.2가 실행되고 위 화면이 나타난다. Next버튼을 눌러 다음 화면으로 진행한다.
 
(4) oraInventory 설치 위치 지정
- 설치 로그 등이 쌓이는 oraInventory 위치를 지정한다. 원래 oraInventory는 oinstall이란 유저를 별도로 만들어서 설치하는 것을 권장하고 있으나, oracle user에서 하는 것이 더 편하다. 아무 문제가 없다.
 
- 우리 설정파일대로 하면 위와 같이 /oracle/oraInventory로 경로가 잡힌다. OK 버튼을 눌러 다음 단계로 진행한다.
 
(5) UNIX 그룹명을 지정
 
- dba 그룹으로 지정한다. Next 버튼을 클릭한다.


(6) orainstRoot.sh 실행
- 그룹을 지정하면 root 권한으로 orainstRoot.sh를 실행해줘야 한다.
- 이 파일은 Oracle의 설치와 소유권한을 가진 그룹을 지정하는 것(dba로 지정)과 Oracle이 설치되는 디렉토리의 위치를 지정한 기록을 생성한다.
- 생성되는 파일은 oraInst.loc 파일로 대개 상용 유닉스의 경우 /var/opt/oracle 디렉토리에 생성되나 이 디렉토리를 미리 만들지 않은 경우 /etc 디렉토리에 생성된다(어디에 생성되든 상관없다)
- 별도 창을 열고 지정된 디렉토리인 /tmp/orainstRoot.sh로 가서 root user가 위 파일을 실행한다.
- 그리고 다시 위 창으로 돌아와서 Continue 버튼을 눌러 설치를 계속한다.


(7) 설치 디렉토리 지정
 
- Path는 .bash_profile에 지정된 경로가 나오게 된다. Next 버튼을 누른다.
 
(8) 설치 Package 선택
- 설치할 방식을 선택한다. 9.2.0.4.0 패치세트가 적용된 설치 파일이 Oracle Technology Network에 있다. 이 파일을 받아서 설치하게 되면 추가로 RPM을 설치할 필요없이 곧바로 설치가 가능하다. 데이터베이스를 설치할 경우는 Oracle 9i Database 9.2.0.4.0을 선택하고, 클라이언트 경우에는 두 번째 항목을 선택하면 된다.
- 하지만, Oracle을 설치하는 서버에서 웹서비스를 하는 경우에는 Oracle 9i Database 9.2.0.4.0 옵션으로 설치할 것을 권한다. REDHAT 9에 기본으로 탑재되는 Apache HTTPD Webserver 2.0.40과 PHP 4.2.2를 기동하여 phpinfo() 함수를 실행해보면 PHP 옵션에 oci 관련 헤더파일이 제외되어 있다. 그런데 Oracle 설치 시 이를 연결하기 위한 oci 관련 source가 클라이언트 옵션으로는 설치되지 않기 때문이다.
- 이 파일의 위치는 $ORACLE_HOME/rdbms/demo 또는 $ORACLE_HOME/rdbms/public(10g의 경우)가 된다.
- 참고로 UNIX/Linux 시스템에서 Apache 2.0.x를 가지고 웹서버를 구성할 경우 예전 1.3.x대에서 처럼 static compile이 불가능하다. 연결될 때마다 라이브러리를 호출하는 DSO 방식으로 설치해야 한다. 이는 아파치와 PHP를 따로따로 컴파일하여 설치하고 후에 Apache 설정파일인 httpd.conf에서 PHP 모듈을 로딩할 수 있도록 정의하면 된다.
- PHP의 경우에는 컴파일 시에 Oracle 라이브러리를 지정해서 컴파일하면 된다.
- Product Languages 버튼을 눌러 Korean을 추가해준다.
- Next 버튼을 눌러 다음 화면으로 이동한다.



(9) 설치할 타입을 선택한다.
- Enterprise Edition 옵션으로 할 것인지, 아니면 Standard 옵션으로 할 것인지 선택해야 한다.
- Custom 설치는 Enterprise 버전을 설치하는 것이다. 이에 포함될 Package를 설치자 재량에 따라 설치하는 것이지만, Standard Edition의 경우 설치자가 옵션을 선택할 권한이 없다. 이미 Standard 버전은 설치할 수 있는 Package가 지정되어 있기 때문에 Standard Edition 내에서 옵션을 customizing하는 것은 불가능하다.
- Enterprise Edition과 Standard Edition의 차이는 다음과 같다 : (표형태로 되어 있어 이 블로그에서는 생략)
- 순수하게 사용되는 공간은 위 그림에 나와 있는 바와 같지만 실제로는 인스턴스 공간까지 요구하므로 최소 약 500MB에서 1.5GB의 공간이 더 요구된다. 이 이상으로 더 잡아야 할 수도 있다. 따라서 최소 Oracle DBMS가 설치되는 경로는 10GB 이상으로 설정한다.
- Oracle 설치 시 archive log mode로 설정하게 되면 $ORACLE_HOME/oradata/K2UP/archive 디렉토리에 archive log 파일이 쌓이게 된다. 특히 개발용이 아닌 실제 데이터베이스를 운영하는 경우라면 필히 설정해야 한다.
- KOLAS II UPGRADE 버전의 경우에는 Custom을 선택하여 굳이 필요없는 옵션을 제외하고 설치할 수 있도록 한다. 그래야 조금이라도 공간이 절약된다. KOLAS II LIGHT의 경우에는 반드시 Standard Edition을 선택한다.
 
(10) Database 사용목적에 따른 설정 옵션을 선택한다
- Custom으로 설치하게 되면 굳이 필요하지는 않지만 습관적으로 선택해주거나 제외하는 옵션이 있다.
- 다음을 추가한다 :
Oracle Label Security
Oracle Connection Manager
Oracle Names
- 다음을 제외한다 :
Oracle Enterprise Manager Products 군 일체
Oracle 9i for UNIX Documentation
Oracle HTTP Server
- 애초부터 선택되어 있지 않는 옵션들은 무시한다.
- 원하는 옵션을 선택하고 Next 버튼을 클릭한다.
- 추가로 설치해야 하는 OUI(Oracle Universal Installer)와 JRE(Java Runtime Environment)가 설치될 위치를 보여준다. 이 파일들은 다른 데 위치해도 되는 것이나 그냥 디폴트대로 설치를 진행한다.
 
(11) Oracle DBA의 권한을 가지는 그룹을 지정한다.
- Oracle에서 Database Instance를 생성한다거나 권한을 제어할 수 있는 그룹을 지정한다. dba가 자동으로 선택되어 있을 것이다.
- 이를테면 한 DBMS에서 문자세트가 다른 인스턴스를 복수로 생성해야 할 경우 같은 그룹에 속하지만 다른 유저를 만들어서 인스턴스를 생성할 수 있다. 예를 들면 dba 그룹에 속하는 oracle이 모든 권한을 가지지만, 같은 그룹 내에 있는 다른 유저인 oracle1이 인스턴스를 생성할 수 있다는 것이다.
- Next 버튼을 눌러 설치를 진행한다.
 
 
(12) 데이터베이스를 생성할 것인지를 결정
- 나중에 dbca(Database Configuration Assistant)를 가지고 별도로 생성할 것이므로 여기서는 No를 선택한다.
- Next 버튼을 클릭한다.
 
(13) 설치할 옵션 선택결과를 보여준다.
- 주의해서 봐야 할 것이 있다 : 예전에는 Enterprise Edition만 사용했던 관계로 Standard Edition 옵션을 주의할 필요가 없었지만 ECOLAS-S, KOLAS II LIGHT 버전은 Standard Edition만을 사용해야 하므로 애초에 처음 설치 시부터 Standard Edition을 선택해야 한다. Installation Type에 따라 아래 화면에서 보이는 것처럼 Global Settings의 Installation Type에 Enterprise Edition, Standard Edition, Custom이 표시된다. 이는 /oracle/oraInventory/logs에 있는 installActions<연월일시>.log에도 그대로 기록이 남게 되므로 주의해야 한다.
- 예를 들면 다음과 같은 형식이다 :
installActions2004-07-22_01-29-32PM.log
- Oracle Products는 제품군마다 일부 기능의 차이가 있고, 이에 따른 라이선스 비용의 차이가 매우 크기 때문에 나중에 문제를 일으키지 않으려면 반드시 아래 그림의 적색 박스로 된 부분을 확인하고 설치해야 한다.
- Install 버튼을 클릭하면 인스톨이 시작된다.
 
(14) 설치과정 중의 에러
- 9.2.0.1.0 버전에서 발생했던 에러는 모두 수정되었다. 설치를 하면서 자동으로 이 부분을 패치를 하고 설치를 진행한다. 참고로 인스턴스 생성 중에 ORA-29807 에러가 발생하는데 다른 상용 UNIX와 마찬가지로 그냥 무시하고 지나가면 된다. 사용할 언어를 영어와 함께 한국어를 넣게 되면 메시지가 이상한 문자로 깨져 나올 것이나 무시하고 지나가면 된다.
- ORA-29807 : specified operator does not exist
Cause : The operator binding which has been specified does not exist.
Action : Ensure that the operator that has been specified does exist.


(15) root.sh의 실행
- 예전에는 /nsr 디렉토리를 만들 것인가하는 질문이 있었는데 그것은 없고 자동으로 만들어버린다. Legato 백업과 관련된 부분인데 사용하지 않는 것이므로 나중에 종료해버리면 된다.
- nsrexecd, nsrd, nsrmmdbd, nsrindexd 이 네 개의 데몬이 root 권한으로 실행된다. 이 실행파일의 위치는 /usr/sbin이다.
- coraenv, dbhome, oraenv 이 세 개 파일이 /usr/local/bin 디렉토리에 생성된다.
- 그리고 Solaris나 AIX와 달리 oraInst.loc 파일과 아래 root.sh를 실행하여 생성되는 oratab 파일은 /var/opt/oracle 디렉토리에 생성되지 않고 /etc 디렉토리에 생성된다.
- 이것으로 선택한 패키지 설치가 완료되었다.


5. 네트워크 관련 설정
DBMS 프로그램 설치가 완료되면 곧바로 리스너 설정으로 들어가게 된다.


(1) 리스너 설정
- 9i부터는 리스너 설정이 끝나면 Oracle Agent 설정을 하게 되는데 상용 UNIX를 제외하고는 Agent 설치에서는 에러가 발생한다. 사용하지 않는 것이니 Next버튼을 눌러 그냥 넘어간다.
 
 
(2) 네트워크 서비스를 설정
- Listener 이외에는 사용할 일이 없다. 기본값이나 설정을 하지 않고 넘어가면 된다.
 


(3) 디렉토리 서비스는 나중에 구성하는 것을 선택한다. 실제로도 할 필요가 없다.
 
(4) 리스너의 이름을 지정한다
- 기본값인 LISTENER 하나만 사용하면 된다. Next 버튼을 클릭한다.
 


(5) 사용할 프로토콜을 선택한다.
- 기본으로 TCP 프로토콜이 선택되어 있다.
 
(6) TCP 프로토콜이 사용할 포트를 선택한다.
- 기본값인 1521을 그대로 사용한다.
 


(7) 또다른 리스너를 만들 것인가를 묻는다.
- No를 선택한다. 나중에 네트워크에 부하가 많이 걸리게 되면 Listener를 여러 개 띄워야 하는 것도 고려해야 한다.
 
(8) 리스너 생성 완료 메시지 확인
 


(9) 이름 지정 메소드를 변경할 것인가를 묻는다.
- 변경할 필요없다. 변경하지 않는다를 선택한다.
 
(10) Oracle Listener 구성이 모두 끝났다.
 


(11) Oracle Agent 설치를 진행
- 설치를 진행하지만 실패한다. 무시하고 넘어간다. 사용않는다.
 
(12) 이로써 네트워크 설정을 포함한 전체 설치 과정이 모두 완료되었다.
 
6. 인스턴스 생성


(1) 인스턴스 생성 시작 화면
- dbca(Database Configuration Assistant)를 사용해서 설치를 시작하는 것이다. 우리가 설치하는 방식으로 테스트해본 결과 전혀 에러가 나지 않았다.
- 단지 에러가 나는 부분은 위에서 말한 것처럼 ORA-29807에러인데 무시하고 설치하면 된다.
- 인스턴스 생성에 문제가 없게 하려면 반드시 사전에 시스템 설정값을 적절히 변경, 적용해놓아야 한다. 또한 shared memory 설정이나 semaphore 부분은 오라클과 서버의 성능에 영향을 주게 되므로, 적절한 값을 계산하여 설정하도록 한다.
- shared memory 설정 변수와 semaphore 값의 의미는 부록을 참조하거나 관련 문서를 보기 바란다.
- Database Configuration Assistant의 시작 : Next 버튼을 클릭한다
 
(2) Database 작업 내용 선택
- 생성, 삭제 또는 변경 등이 가능하다.


(3) 데이터베이스 생성방식을 선택한다. 우리는 New Database를 선택한다.
 
(4) Global Database Name과 SID를 지정한다.
- 다르게 해도 되지만 되도록 같게 지정한다.


(5) 필요없는 옵션은 모두 제외한다
- Oracle Text를 제외한 모든 옵션을 삭제하고 관련 데이터베이스를 생성하지 않는다.


(6) 서버 모드는 전용서버모드(Dedicated Server Mode)로 한다.
- 기본적으로 서버에서 Database만 운영하므로 전용서버모드로 설정하고 경우에 따라서 인스턴스가 2개 이상 된다거나 아니면 한 서버에서 여러 서비스를 제공하는 경우라면 공유서버모드로 해도 된다. 공유서버모드로 하게 되면 하나의 프로세스를 여러 클라이언트가 공유할 수 있게 된다.
- 다음 화면에서 보겠지만 All initialization parameters라는 메뉴가 있다. 단순하게 보기만 하는 것이지만 여기에 init<SID>.ora에 설정되는 모든 설정값의 정의가 있다. 참고하기 바란다.
 
(7) 생성할 인스턴스에 대한 설정을 한다.
- Typical로 하게 되면 전체 메모리를 가지고 자동으로 SGA를 계산해주지만 Custom으로 하게 되면 설치자 재량에 따라 설정할 수 있다.
- 사용할 문자세트를 선택한다.
- DB 크기를 결정한다. block size는 리눅스의 경우 최대 32KB까지이므로 많은 데이터를 한꺼번에 처리하게 된다면 block size를 늘릴 필요가 있다.
- 파일이 생성될 위치를 지정한다. 그냥 디폴트 경로를 사용한다.
- archive log 사용 여부를 결정한다. 개발용이면야 구태여 archive log를 사용할 필요가 없겠지만 실수요자나 백업 소프트웨어를 사용하는 경우 반드시 설정해야 한다.
- Next 버튼을 클릭한다.


(8) Database Storage의 크기를 결정한다
- 별다른 조정없이 디폴트값을 사용해도 되지만 변경해야 한다면 여기서 미리 바꿔도 된다.
- 나중에 alter database … 구문으로 파일의 크기를 늘릴 수 있다.
- DBF 파일은 자동으로 확장되는 지만 확인하면 되고 만약 안되어 있으면 자동으로 확장될 수 있도록 설정해준다. 기본값으로 대개 640KB 정도가 잡혀 있으나 전체 프로세스와 트랜잭션을 감안하여 증가되는 크기를 10MB 이상 잡는 것을 권한다.
- 어차피 데이터가 DBF 파일을 다 채워야만 증가하는 것이므로 공간을 넉넉하게 잡아주도록 한다.
- 연필 아이콘을 눌러 DB 크기를 조정한다.
- 블록 사이즈도 조정해준다. 끝나면 Next 버튼을 클릭한다.
- DB 생성 스크립트가 필요하다면 체크해서 생성되도록 한다.(먼저 생성됨)
- Finish 버튼을 클릭한다.
- 다음과 같은 결과를 HTML로 보여준다. OK버튼을 클릭한다.
 
(9) 인스턴스가 생성될 때까지 기다린다.
- 그다지 많은 옵션을 준 것이 아니므로 시간이 많이 걸리지는 않는다.
 
- DB 생성 중에 다음과 같은 에러 메시지가 나온다. 무시하고 넘어간다. 계속 설치가 진행된다.
 
 
(10) 암호설정이 마지막 작업이다. Exit하면 DB 생성까지 종료된다.
 
- 이것으로 모든 설치가 종료되었다.
 
Setting Shared Memory


Shared memory allows processes to access common structures and data by placing them in shared memory segments. It’s the fastest form of IPC (Interprocess Communication) available since no kernel involvement occurs when data is passed between the processes. In fact, data does not need to be copied between the processes.
Oracle uses shared memory segments for the SGA (Shared Global Area) which is an area of memory that is shared by all Oracle background and foreground processes. The size of the SGA has a major impact to Oracle’s performance since it holds database buffer cache and much more.
To see all shared memory settings, run:
ipcs -lm


Setting SHMMAX Parameter


This parameter defines the maximum size in bytes for a shared memory segment. Since the SGA is comprised of shared memory, SHMMAX can potentially limit the size of the SGA. Ideally, SHMMAX should be large enough so that SGA can fit into one segment.
The default size on RH 2.1 AS is 33554432. With this value, the Oracle Database Configuration Assistant failed on my server with the following error message:
ORA-27123: unable to attach to shared memory segment
Setting SHMMAX to 1 GB always worked for me when I setup a medium sized database. However, it is suggested that it should be set to 2 GB; the default maximum size of the SGA is 1.7 GB which requires a larger SHMMAX. And if the available size of the SGA is set to 2.7 GB by changing “mapped base” at the Linux OS level, then SHMMAX should be set to 3 GB. The maximum value of SHMMAX can be set to 4GB-1. (A typical 32-bit Linux system without Physical Address Extension (PAE) is divided into 3 GB user space and 1 GB kernel space.)


The default shared memory limit for SHMMAX can be changed in the proc file system without reboot:
su – root
echo “2147483648″ > /proc/sys/kernel/shmmax
Alternatively, you can use sysctl(8) to change it:
sysctl -w kernel.shmmax=2147483648
To make the change permanent, add the following line to the file /etc/sysctl.conf. This file is used during the boot process.
echo “kernel.shmmax=2147483648″ >> /etc/sysctl.conf


Setting SHMMNI Parameter


This parameter sets the maximum number of shared memory segments system wide. The default number on RH 2.1 AS is 4096. To my knowledge this value should be sufficient.
# cat /proc/sys/kernel/shmmni
4096


Setting SHMALL Parameter


This parameter sets the total amount of shared memory in pages that can be used at one time on the system. So shmall should always be at least ceil(SHMMAX/PAGE_SIZE).


The default size for shmall on RH 2.1 AS is 2097152. This should be sufficient since it means that the total amount of shared memory available on the system is 2097152*4096 bytes (shmall*PAGE_SIZE). On i386 architectures, the PAGE_SIZE in RHAS 2.1 (UP and SMP kernel) is 4096 bytes unless you use bigpages which supports the configuration of larger memory pages.
# cat /proc/sys/kernel/shmall
2097152



Setting Semaphores


Semaphores can best be described as counters which are used to provide synchronization between processes or between threads within a process for shared resources like shared memories. System V semaphores support semaphore sets where each one is a counting semaphore. So when an application requests semaphores, the kernel releases them in “sets”. The number of semaphores per set can be defined through the kernel parameter SEMMSL.


To see all semaphore settings, run:
ipcs -ls


The SEMMSL Parameter


This parameter defines the maximum number of semaphores per semaphore set.


Oracle recommends to set SEMMSL to the largest PROCESSES init.ora parameter of any database on the Linux system plus 10.
Oracle also recommends to set SEMMSL to a minimum value of 100.


The init.ora parameter PROCESSES specifies the maximum number of operating system processes that can be started by the Oracle instance. In a non MTS environment, Oracle spawns a system user process for each connection. This means that in such an environment the PROCESSES parameter defines the maximum number of simultaneous Oracle connections minus sum of all Oracle background processes.
It can also be said that the PROCESSES value should never be greater than SEMMSL.


The SEMMNI Parameter


This parameter defines the maximum number of semaphore sets in the entire Linux system.


Oracle recommends to set SEMMNI to a minimum value of 100.


The SEMMNS Parameter


This parameter defines the total number of semaphores (not semaphore set) in the entire Linux system. A semaphore set can have more than one semaphore, and according to the semget(2) man page, values greater than SEMMSL * SEMMNI makes it irrelevant.


Setting it to a minimum value of 256 is for initial Oracle installation only.
Oracle recommends to set SEMMNS to the sum of the PROCESSES parameter for each database on the system, adding the largest PROCESSES twice, and then adding 10 for each DB.


The maximum number of semaphores that can be allocated on a Linux system will be the lesser of:
   SEMMNS or (SEMMSL * SEMMNI)


Setting SEMMSL and SEMMNI to 100 makes sure that SEMMNS semaphores can be allocated as determined by the above calculation.


The SEMOPM Parameter


This parameter defines the maximum number of semaphore operations that can be performed per semop(2) system call.


The semop(2) function provides the ability to do operations for multiple semaphores with one semop(2) system call. Since a semaphore set can have the maximum number of SEMMSL semaphores per semaphore set, it is often recommended to set SEMOPM equal to SEMMSL.


Oracle recommends to set SEMOPM to a minimum value of 100.



Setting the Semaphore Kernel Parameters


To determine the values of the four described semaphore parameters, run:
# cat /proc/sys/kernel/sem
250     32000   32      128
Alternatively, you can run:
ipcs -ls
All four described semaphore parameters can be changed in the proc file system without reboot:
su – root
# echo SEMMSL_value SEMMNS_value SEMOPM_value SEMMNI_value > /proc/sys/kernel/sem
# These are the values I’m using since I don’t want to lower Red Hat’s default
# values. The only value I raise is SEMOPM to comply with Oracle’s minimum
# requirement for SEMOPM.
echo 250 32000 100 128 > /proc/sys/kernel/sem
Alternatively, you can use sysctl(8) to change it:
sysctl -w kernel.sem=”250 32000 100 128″
To make the change permanent, add or change the following line in the file /etc/sysctl.conf. This file is used during the boot process.
echo “kernel.sem=250 32000 100 128″ >> /etc/sysctl.conf
To see the new updated semaphore settings, run:
ipcs -ls



Copyright ⓒ 2004 Yi, Seung-Ro. All rights reserved.

[펌] index 분할을 이용한 리스트 속도향상

0

index 분할을 이용한 리스트 속도 향상

게시판에서 자료가 쌓여 갈수록 속도가 느려집니다.
이유는 다들 아시다 시피 index 를 이용하더라도

select * from ez_board_test order by bid desc limit 100000,10
실행속도 14.110 sec
하면 속도가 많이 느려집니다.
실제로 거의 모든 게시판은 저장된 시간이 오래된 것일수록 뒤로 가야 하기 때문에 글이 쎃이면 쌓일수록 limit x,y 에서 x 의 값이 커질수 밖에 없습니다.

이러한 속도를 빨라지게 하기 위해서 index 분할을 이용합니다.

index 분할 이란 각각의 게시물을 그룹별로 묶어서 리스트에 접근시 해당 그룹 내에서만 select 한다는데 장점이 있습니다.

select * from ez_board_test order by bid desc limit 100000,10
이 아닌
select * from ez_board_test where index_id=100 order by bid desc limit 150,10

과 같은 형태로 찾아는 것입니다.

이러한 쿼리문은 먼저 index_id 값을 가진 게시물을 전체에서 선별해서 그 안에서 order by 와 limit 가 일어나기 때문에 모든 게시물을 전체 불러와야 하는 부담이 적다는데 그 목적과 장점이 있습니다.

제가 만든 게시판의 경우에는 5000 개 단위로 index 값을 나누어 두었습니다.
이 방법을 사용하면 모든 페이지에서 게시물 리스트 속도가 0.1초를 넘어가지 않게 됩니다.
이 알고리즘의 기본적인 테이블 구조를 말씀드리겠습니다.

index 저장 테이블
index_id smallint(3) not null primary key 아이디 값 저장
count smallint(4) not null default’0′ 해당 index 가 가지는 게시물 수(게시물이 많이지면 전부 5000 개를 가지게 됩니다.)
total_num int(11) unsigned not null 현재 index 와 지난 index 들이 가지는 총 게시물 수

게시물 저장 테이블
index_id smallint(3) not null
bid int(11) unsigned not null auto_increment primary key
기타 제목 내용등 저장 필드들
key index_index(index_id)

위와 같은 구조로 리스트 시에 아래와 같은 쿼리문을 만들어 쓰고 있습니다.

SELECT board.bid, board.fid, board.depth, board.uid, board.cid, if(board.uid,ez_user.nickname,board.name) as name, ifnull(ez_user.icon,”) as icon, board.subject, board.content, board.hit, board.vote, board.comment_cnt, board.secret, board.deleted, board.signdate, board.file_name FROM ez_board_test board LEFT JOIN ez_user ON board.uid=ez_user.uid WHERE board.index_id = 68 order by board.fid desc,board.depth LIMIT 0,10

현재 게시물 30만 약간 넘은 테스트 게시판의 실제 쿼리문입니다.
중간에 사용자 테이블과의 조인이 좀 있어서 속도가 많이 걱정이 되긴 하지만 5000 개 내에서 아무리 조인을 해도 체감속도에는 거의 지장이 없습니다.

Go to Top