데이터베이스 2015. 12. 21. 22:10

mysql은 master slave 구조의 복제 구조를 갖을 수 있다.

근데 이 구조가 과연 괜찮을 것인가?는 의문이다. 

자동 fail over 라는 관점에서는 그럴 수 있을 지 몰라도.

장비당 request를 처리함을 목적으로 늘리는 것은 좀.. 

그러던중 특정 노드(slave)사에 혹은 master slave 사이의 네트웍 peak 상태가 된다면.. ㅈㅈ

리플리케이션 지연이 일어나고.. master slave사이의 정합성이 깨지더라...

결국 해결 방법은 master slave를 한랙에 구성하고 그 둘사이를 본딩(nic)을 하던.. 10G로 구성을 하던.. 

물론 그 사이에 트래픽을 마구 끼워 넣는 로직을 방지해야지만....

'데이터베이스' 카테고리의 다른 글

mysql 날짜 함수  (0) 2015.12.16
LEFT Outer JOIN  (0) 2015.01.13
MySQL 비밀번호 복구  (0) 2014.05.31
mysql 패스워드 분실시에  (0) 2014.04.04
오라클 scott 유저 활성화  (0) 2013.11.04
//
데이터베이스 2015. 12. 16. 14:45

mysql  

한달전 where reg_date >= date_add(now(), interval -1 month)  
하루전 where reg_date >= date_add(now(), interval -1 day)  
한시간전 where reg_date >= date_add(now(), interval -1 hour)  

 
기타 날짜 조건 

select date_format(D_time,"%Y-%m-%d") from 테이블명 
select date_format(D_time,"%H:%i::%s") from 테이블명  

D_time 오늘인거 가져오기 

select D_time from 테이블명 where date_format(D_time,"%Y-%m-%d") = current_date; 
  

등록된지 24시간이 안된거 가져오기 

select D_time from 테이블명 where D_time > date_sub(now(), interval 1 day); 

'데이터베이스' 카테고리의 다른 글

데이터베이스(MySql)의 replication과 network  (0) 2015.12.21
LEFT Outer JOIN  (0) 2015.01.13
MySQL 비밀번호 복구  (0) 2014.05.31
mysql 패스워드 분실시에  (0) 2014.04.04
오라클 scott 유저 활성화  (0) 2013.11.04
//
데이터베이스 2015. 1. 13. 17:07


1. OUTER JOIN

INNER JOIN이 JOIN 조건에 부합하는 행만 JOIN이 발생하는 것이라면, 
OUTER JOIN은 조건에 부합하지 않는 행까지도 포함시켜 결합하는 것을 의미한다.

자주는 아니지만, 가끔 유용하게 사용될 수 있으므로 꼭 알아둘 필요는 있다.

기본 구문은 아래와 같다.

  1. SELECT <열 목록>
  2. FROM <첫번째 테이블 (LEFT 테이블)>
  3.     <LEFT | RIGHT | FULL> OUTER JOIN <두번째 테이블 (RIGHT 테이블)>
  4.                           ON <조인될 조건>
  5. [WHERE 검색 조건]

INNER JOIN과 유사해 보이지만, LEFT, RIGHT, FULL의 새로운 키워드들이 보인다.


2. LEFT OUTER JOIN

LEFT OUTER JOIN은 왼쪽 테이블의 것은 조건에 부합하지 않더라도 모두 결합되어야 한다는 의미이다.

즉, FROM 첫번째 테이블 LEFT OUTER JOIN 두번째 테이블이라면, 첫번째 테이블의 것은 모두 출력되어야 한다.
예제를 살펴 보자.

  1. -- 전체 회원의 구매기록을 살펴보자.
  2. -- 단, 구매 기록이 없는 회원도 출력되어야 한다.
  3.  
  4. -- LEFT OUTER JOIN이므로, UserTable은 모두 출력된다
  5.  
  6. SELECT U.ID, Name, GoodName, Addr
  7. FROM UserTable U                    -- LEFT Table    
  8.         LEFT OUTER JOIN BuyTable B  -- RIGHT Table
  9.         ON U.ID = B.ID
  10. ORDER BY U.ID

INNER JOIN시 INNER 키워드를 생략 가능했던 것처럼,
LEFT OUTER JOIN 역시 LEFT JOIN만으로 작성해도 무방하다.

위 예제의 결과는 아래와 같다. (모든 UserTable의 행이 출력되었다)



3. RIGHT OUTER JOIN

RIGHT OUTER JOIN은 오른쪽 테이블의 것은 조건에 부합하지 않더라도 모두 결합되어야 한다는 의미이다.

즉, FROM 첫번째 테이블 RIGHT OUTER JOIN 두번째 테이블이라면, 두번째 테이블의 것은 모두 출력되어야 한다.
LEFT OUTER JOIN의 예제와 동일한 결과를 얻을 수 있도록 예제를 작성해 보자.

  1. -- 전체 회원의 구매기록을 살펴보자.
  2. -- 단, 구매 기록이 없는 회원도 출력되어야 한다.
  3.  
  4. -- RIGHT OUTER JOIN이므로, UserTable은 모두 출력된다
  5.  
  6. SELECT U.ID, Name, GoodName, Addr
  7. FROM BuyTable B                       -- LEFT Table    
  8.         RIGHT OUTER JOIN UserTable U  -- RIGHT Table
  9.         ON B.ID = U.ID
  10. ORDER BY U.ID

역시 RIGHT OUTER JOIN은 RIGHT JOIN만으로도 작성이 가능하다.


4. FULL OUTER JOIN

전체 조인 또는 전체 외부 조인이라고 한다.
FULL OUTER JOIN은 LEFT OUTER JOIN과 RIGHT OUTER JOIN을 합친 것이라고 생각하면 된다.

즉, 한쪽을 기준으로 조건과 일치하지 않는 것을 출력하는 것이 아니라,
양쪽 모두에 조건이 일치하지 않는 것들까지 모두 결합하는 개념이다.

따라서, 테이블들의 모든 행이 조건에 관계없이 결합된다.


5. 세 개 이상의 테이블 조인

INNER JOIN 문서의 예제를 재활용하자.

INNER JOIN 예제를 보면, 동아리에 가입하지 않은 '김제둥'은 결과에 포함되지 않았다.
이를 OUTER JOIN으로 동아리에 가입하지 않은 학생까지 출력되도록 예제를 작성해 보자.

  1. SELECT S.Name, Addr, C.Name, RoomNo
  2. FROM StudentTable S
  3.         -- 먼저 StudentTable이 모두 출력될 수 있도록 StdClubTable과 LEFT OUTER JOIN
  4.         LEFT OUTER JOIN StdClubTable SC
  5.         ON S.Name = SC.StdName
  6.             -- 그 결합에 다시 ClubTable을 LEFT OUTER JOIN
  7.             LEFT OUTER JOIN ClubTable C
  8.             ON SC.ClubName = C.Name

결과는 다음과 같이 동아리에 가입하지 않은 '김제둥'도 출력되었다.


이번엔 학생 기준이 아닌, 동아리를 기준으로 가입된 학생을 출력하되,
가입 학생이 하나도 없는 동아리라도 출력될 수 있도록 예제를 작성해 보자.

  1. SELECT C.Name, RoomNo, S.Name, Addr
  2. FROM StudentTable S
  3.         -- 먼저 StudentTable이 모두 출력될 수 있도록 StdClubTable과 LEFT OUTER JOIN
  4.         LEFT OUTER JOIN StdClubTable SC
  5.         ON S.Name = SC.StdName
  6.             -- 이후 클럽이 모두 출력될 수 있도록 ClubTable이 결합 결과를 RIGHT OUTER JOIN
  7.             RIGHT OUTER JOIN ClubTable C
  8.             ON SC.ClubName = C.Name

결과는 아래와 같다.


사실 위 예제에서 동아리에 가입하지 않은 학생의 경우 최종 목적 출력에 아무런 의미가 없으므로, 
아래와 같이 작성하는 것이 더욱 깔끔하고 성능도 조금 더 낫다.

  1. SELECT C.Name, RoomNo, S.Name, Addr
  2. FROM StudentTable S
  3.         -- StudentTable과 StdClubTable을 INNER JOIN하여 동아리에 가입한 학생을 추출하고,
  4.         INNER JOIN StdClubTable SC
  5.         ON S.Name = SC.StdName
  6.             -- 모든 클럽이 출력될 수 있도록 위 INNER JOIN의 결합 결과를 
                -- ClubTable이 다시 RIGHT OUTER JOIN
  7.             RIGHT OUTER JOIN ClubTable C
  8.             ON SC.ClubName = C.Name



참조 : http://egloos.zum.com/sweeper/v/3002220

'데이터베이스' 카테고리의 다른 글

데이터베이스(MySql)의 replication과 network  (0) 2015.12.21
mysql 날짜 함수  (0) 2015.12.16
MySQL 비밀번호 복구  (0) 2014.05.31
mysql 패스워드 분실시에  (0) 2014.04.04
오라클 scott 유저 활성화  (0) 2013.11.04
//
데이터베이스 2014. 5. 31. 17:05

Step # 1 : Stop mysql service

# /etc/init.d/mysql stop
Output:

Stopping MySQL database server: mysqld.

Step # 2: Start to MySQL server w/o password:

# mysqld_safe --skip-grant-tables &
Output:

[1] 5988
Starting mysqld daemon with databases from /var/lib/mysql
mysqld_safe[6025]: started

Step # 3: Connect to mysql server using mysql client:

# mysql -u root
Output:

Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 1 to server version: 4.1.15-Debian_1-log
Type 'help;' or '\h' for help. Type '\c' to clear the buffer.
mysql>

Step # 4: Setup new MySQL root user password

mysql> use mysql;
mysql> update user set password=PASSWORD("NEW-ROOT-PASSWORD") where User='root';
mysql> flush privileges;
mysql> quit

Step # 5: Stop MySQL Server:

# /etc/init.d/mysql stop
Output:

Stopping MySQL database server: mysqld
STOPPING server from pid file /var/run/mysqld/mysqld.pid
mysqld_safe[6186]: ended
[1]+  Done                    mysqld_safe --skip-grant-tables

Step # 6: Start MySQL server and test it

# /etc/init.d/mysql start
# mysql -u root -p

'데이터베이스' 카테고리의 다른 글

mysql 날짜 함수  (0) 2015.12.16
LEFT Outer JOIN  (0) 2015.01.13
mysql 패스워드 분실시에  (0) 2014.04.04
오라클 scott 유저 활성화  (0) 2013.11.04
DB index 사용하기  (0) 2013.10.15
//
데이터베이스 2014. 4. 4. 14:52

1. 데몬을 죽인다.

# killall mysqld

2. skip grant 모드로 데몬 실행

# mysqld_safe --skip-grant &

3. mysql 실행

# mysql

4. root 비번 업데이트

mysql> update user set password=password('새패스워드') where user='root';
mysql> flush privileges;

5. 데몬 재실행

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

1. 작업관리자를 띄워서 mysql 데몬(mysqld.exe 프로세스)를 죽인다.

2. mysql 데몬에 옵션을 줘서 다시 띄우기...

C:\Program Files\MySQL\MySQL Server 5.1\bin>mysqld --skip-grant

3. 다른 커맨드 창에서 mysql 실행 - 암호없이 가능!

4. MySql 프롬프트 상태에서 암호 변경

mysql> use mysql
Database changed
mysql> update user set password=password('*******') where user='root';
Query OK, 1 row affected (0.33 sec)
Rows matched: 1  Changed: 1  Warnings: 0

mysql> flush privileges 

'데이터베이스' 카테고리의 다른 글

LEFT Outer JOIN  (0) 2015.01.13
MySQL 비밀번호 복구  (0) 2014.05.31
오라클 scott 유저 활성화  (0) 2013.11.04
DB index 사용하기  (0) 2013.10.15
mysql 기본사용  (0) 2013.01.20
//
데이터베이스 2013. 11. 4. 02:53

Oracle 11g XE가 설치된 경로(디폴트, c:\oraclexe)에서 검색하여 scott.sql 파일을 찾고 그 경로를 복사한다.

시작 > Oracle 11g XE > Run SQL CommandLine > 커맨드 창에 위에서 복사한 내용을 이용하여 다음과 같이 입력한다.

 


SQL> conn /as sysdba

SQL> @C:\oraclexe\app\oracle\product\11.2.0\server\rdbms\admin\scott.sql<enter>

SQL> alter user scott identified by tiger;<enter>

SQL> conn scott/tiger;<enter>

SQL> select * from emp;<enter>


'데이터베이스' 카테고리의 다른 글

MySQL 비밀번호 복구  (0) 2014.05.31
mysql 패스워드 분실시에  (0) 2014.04.04
DB index 사용하기  (0) 2013.10.15
mysql 기본사용  (0) 2013.01.20
mysql 사용자 권한 넣기  (0) 2013.01.02
//
데이터베이스 2013. 10. 15. 14:39


데브피아에서 기가 막히게 좋은 전문가 글을 찾았습니다. 간단하게 정리해 봅니다.

인덱스를 사용하기를 기대하지만 그렇지 않은 기본적이고 대표적인 예입니다.

1. 인덱스 컬럼을 변형하여 비교할 때

BAD
WHERE TO_CHAR(HIREDATE,'YYYYMMDD') = '19980518';
GOOD
WHERE HIREDATE = TO_DATE('19980518')


BAD
WHERE SALARY + 1000 > 100000;
GOOD
WHERE SALARY > 100000 - 1000;


비교하는 인덱스 컬럼의 형이나 값을 변경하면 발생합니다.
이 경우에는 비교값을 변경해 주어야 인덱스를 사용하게 됩니다.

2. 비교 대상의 형이 달라서 내부적으로 형변환을 하는 경우

BAD
WHERE EMP_ID = 200383;
GOOD
WHERE EMP_ID = ‘200383’;


EMP_ID가varchar라고 할 경우에 비교값이 숫자인 경우에 DB에서 자동으로 이를 숫자로 변경하고 비교하게 됩니다. 이 경우에 인덱스 컬럼에 변형이 일어났기 때문에 인덱스를 사용하지 못하게 됩니다.

3. NULL을 비교하는 경우

BAD
WHERE JOB IS NULL;


일반적으로 Oracle을 기준으로 NULL은 인덱스 대상이 아니라고 합니다. 따라서, 이를 해결하기 위해서는 NULL을 쓰지 말고 다른 정해진 값을 이용해서 비교해야 합니다. (흠..이건 좀...)

4. 부정형 조건인 경우

BAD
WHERE JOB NOT IN ( 'INSTRUCTOR','STAFF'); 


부정형 역시 인덱스를 사용하지 못하는 대표적인 조건 쿼리 입니다. 아닌 놈을 찾으려면 전체를 뒤지는 수 밖에요. 이를 피하기 위한 근본적인 DB 모델링이 중요합니다.


이하 원문을 그대로 가져다 붙입니다. 추가 설명이 필요하면 읽어 보세요.
http://www.devpia.com/DevStudy/Lecture/OffLineDetail.aspx?nSemiID=1429&lectype=evt

필자가 처음에 SQL을 배울 때 SQL이 상당히 이상했다. 원하는 것만 요구할 뿐 어떻게 가져오라는 정보가 SQL에는 없었기 때문이다. FILE레벨의 I/O까지 코딩에 익숙한 필자에게 절차가 없다는 것이 오희려 더 이상했던 것이다.
물론 상세한 과정이 필요하지 않으므로 편리하고 좋았다 그러나 어떻게 가져오는지는 알지못하고 단지 사용할 뿐이었다.
그러나 SQL이 PLAN이라는 실행 계획을 만들고 그에 따라 가져오게 된다는 사실은 안것은 한참 뒤에 일이었다.
저자소개: 유원석
(現) (주)위즈베이스 컨설팅본부 수석컨설턴트
프로젝트 :
ㆍ하나투어 DB아키텍터
ㆍSK Telecom NGM Project 시스템 성능관리자
ㆍKT EDW Projec Main Architect 수행
ㆍLG 전자 Eagle Project 시스템 성능 개선 등
강 의 :
ㆍ한국썬마이크로시스템즈 대용량데이터베이스
ㆍ한국썬마이크로시스템즈 Orange를 이용한 DB튜닝
결국은 내가 하지않은 일을 Optimizer라는 프로그램이 대신 해주고 있는 것이 아닌가? 그래서 정말 고마운 놈이라고 생각했었다. 그러나 밑는 도끼에 발등을 찍힌다는 말이 있지 않은가?
Plan에 index를 달아주어도 Index를 사용하지 않고 full table scan만 하고 있으니 당체 속도가 나지를 않았다.
이래저래 해서 나중에 알게되었지만 결국 컬럼의 변형을 가하면 index를 사용하지 못한다는 것이다. 우리가 직접 사용하지는 않지만 결국 우리가 SQL을 사용한다는 것은 Optimizer라는 놈에게 SQL의 수행을 부탁하는 것이다. 따라서 우리가 Optimizer에 대해서 잘 안다면 SQL을 좀더 효율적으로 수행하도록 할 수 있지 않은가!
그러면 인덱스를 달았을 때 Optimizer가 index를 사용하지 못하는 경우를 통해서 우리가 애써(?)생성한 인덱시가 무용지물이 되지 않도록 해보자.
아래예제에 사용할 TABLE LAYOUT이다.
EMPLOYEES
---------
Rows=15,132
Empty Blocks=7
Chain Count=0
Avg Space Freelist Blocks=0
Sample Size=15,132
Partitioned=NO

Blocks=121
Avg Space=885
Avg Row Length=51
Freelist Blocks=0
Last Analyze=2009/05/04
Column Name
---------------
EMP_ID
MGR_ID
LAST_NAME
FIRST_NAME
HIREDATE
JOB
SALARY

Nullable
-----------------


NOT NULL
Column Type
-----------------
VARCHAR2(40)
VARCHAR2(40)
VARCHAR2(24)
VARCHAR2(14)
DATE
VARCHAR2(24)
NUMBER(7,2)
Distinct
-----------------
15,132 
679 
9,443 
3,579 
3,903 
53 
3,267
Buckets
------------------
75
75
75
75
75
53
75
INDEX
--------------------------------------------------------------------------------------
IDX_GENDER : GENDER
      Type=NORMAL, Uniq=No, Distinct=2, Rows=15,132, Last Analyze=2009/05/04
IDX_HIREDAT : HIREDATE
      Type=NORMAL, Uniq=No, Distinct=3,903, Rows=15,132, Last Analyze=2009/05/04
IDX_JOB : JOB
      Type=NORMAL, Uniq=No, Distinct=53, Rows=15,129, Last Analyze=2009/05/04
IDX_SALARY : SALARY
      Type=NORMAL, Uniq=No, Distinct=3,267, Rows=15,132, Last Analyze=2009/05/04
IDX_TYPE2 : TYPE
      Type=NORMAL, Uniq=No, Distinct=6, Rows=15,132, Last Analyze=2009/05/04
PK_EMP_ID : EMP_ID
      Type=NORMAL, Uniq=No, Distinct=15,132, Rows=15,132, Last Analyze=2009/05/04
필자가 여러군데 튜닝을 하면서 가장 많이 본것중에 하나는 INDEX를 달았으나 쓰지 못하게 되는 경우이다. 대표적인 경우가 아래와 같이 날짜타입(HIREDATE)에 TO_CHAR를 씌운 경우이다.
SELECT FIRST_NAME, LAST_NAME
FROM EMPLOYEES
WHERE TO_CHAR(HIREDATE,'YYYYMMDD') = '19980518';
물론 INDEX는 아래와 같이 생성되어있다.
CREATE INDEX IDX_HIREDATE ON EMPLOYEES(HIREDATE);
우리가 원하는 것은 INDEX를 타고 테이블을 가져오기를 바란것이었다.

그러나 실제 PLAN은 아래와 같이 나온다.
Execution Plan
--------------------------------------------------------------------------------
0 SELECT STATEMENT Optimizer=ALL_ROWS (Cost=28 Card=151 Bytes=3K)
1 0 TABLE ACCESS (FULL) OF 'EMPLOYEES' (TABLE) (Cost=28 Card=151 Bytes=3K)
TABLE ACCESS (FULL) 이란 뜻은 INDEX를 타지 않고 테이블을 처음부터 끝까지 읽어서 찾는다는 뜻이다. 한마디로 10건이며 10건읽고 100만건이면 100만건을 다 읽어야 결과가 나온다는 말이다.

OPEN시에는 빠르던 시스템이 시간이 지날수록 느려지는 결정적인 역할을 하는 것이 바로 위와 같은 경우이다. 그럼 어떻게 해야 제대로 인덱스를 사용할 수 있을가?
일단 간단히 SQL의 수정으로 해결할수 있다. HIREDATE는 날짜 타입이다.
따라서 인덱스를 HIREDATE로 했을 때 인덱스를 타기위해서는 INDEX를 생성한것에 변형을 주어서는 안된다.
SELECT FIRST_NAME, LAST_NAME
FROM EMPLOYEES
WHERE HIREDATE = TO_DATE('19980518')
따라서 간단하게 위와 같이 고치면 INDEX를 사용하게된다.
Execution Plan
--------------------------------------------------------------------------------
0 SELECT STATEMENT Optimizer=ALL_ROWS (Cost=3 Card=4 Bytes=92)
1 0 TABLE ACCESS (BY INDEX ROWID) OF 'EMPLOYEES' (TABLE) (Cost=3 Card=4 Bytes=92)
2 1 INDEX (RANGE SCAN) OF 'IDX_HIREDATE' (INDEX) (Cost=1 Card=4)
물론 결과도 빠르게 나온다 그러나 중요한 점이 있다 결과가 같을까?
운이 좋으면 결과가 같을 것이고 대부분의 경우는 결과가 틀리다.
왜 그럴까?
날짜 타입은 날짜와 시분초의 정보도 가지고 있다. 따라서 TO_DATE(‘19980518’)라는 말은 정확히 1998년5월18일 0시0분0초라는 뜻이다. 그래서 우리가 원하는 1998년5월18일자와는 차이가 있다.
따라서 1998년5월18일 0시0분1초 ~ 23시59분59초까지의 데이터는 나오지 않게되는것이다.
이것은 튜닝할 때 유의할 점이다. 결과를 같게 유지해야하는것이다. 이 상황을 알고있다면 방법은 간단하다.
아래아 같이 고치면 빠른시간에 원하는 결과를 얻을 수 있을 것이다.
SELECT FIRST_NAME, LAST_NAME
FROM EMPLOYEES
WHERE HIREDATE BETWEEN TO_DATE('19980518'||'00:00:00','YYYYMMDD HH24:MI:SS')
AND TO_DATE('19980518'||'23:59:59','YYYYMMDD HH24:MI:SS')
비슷하지만 함수의한 변형이 아닌 간단한 연산에의한 변형의 경우도 마찬가지이다.
$1000의 인센티브를 더주면 $10000이 넘는 사람을 찾는 SQL을 만들어보자.
아마 아래와 같을 것이다.
SELECT FIRST_NAME, LAST_NAME
FROM EMPLOYEES
WHERE SALARY + 1000 > 100000;
물론 INDEX는 아래와 같이 만들었다.
CREATE INDEX IDX_SALARY ON EMPLOYEES(SALARY);
그러나 PLAN을 보자
Execution Plan
--------------------------------------------------------------------------------
0 SELECT STATEMENT Optimizer=ALL_ROWS (Cost=29 Card=757 Bytes=13K)
1 0 TABLE ACCESS (FULL) OF 'EMPLOYEES' (TABLE) (Cost=29 Card=757 Bytes=13K)
인데스를 타지 못한다. 왜일까. 간단한 연산이지만 SALARY컬럼에 가공을 했기 때문에 OPTIMIZER는 인덱스를 타는 것을 포기해버린다.
따라서 우리가 기초적인 수학 실력을 발휘해서 이항을 해준다면 아래와 같은 조건이 될것이다.
SELECT FIRST_NAME, LAST_NAME
FROM EMPLOYEES
WHERE SALARY > 100000 - 1000;
이경우에 PLAN을 보자.
Execution Plan
--------------------------------------------------------------------------------
0 SELECT STATEMENT Optimizer=ALL_ROWS (Cost=3 Card=1 Bytes=17)
1 0 TABLE ACCESS (BY INDEX ROWID) OF 'EMPLOYEES' (TABLE) (Cost=3 Card=1 Bytes=17)
2 1 INDEX (RANGE SCAN) OF 'IDX_SALARY' (INDEX) (Cost=2 Card=1)
재미 있게도 이번에 제대로 된 인덱스를 탄다. Optimizer가 바보 같다는 생각이 들지 않는가?
물론 바보같다. 그러나 OPTIMIZER나름대로 깊은 고민이 있다. 아주 잛은 시간내에 OPTIMIZER는 많은 경우의 수를 타진해야한다. 따라서 이항연산과 같은 것 까지 검토하면 너무 많은 시간을 소모하게 된다 따라서 그런부분은 포기한것이다.

또다른 경우중에 하나가 DB의 내부적인 변형이다. 이는 개발자가 의도하지 않게 문제를 야기하는 경우이다.
여기 PK 조건으로 검색하는 SQL이 있다.
SELECT LAST_NAME,FIRST_NAME
FROM EMPLOYEES
WHERE EMP_ID = 200383;
그러나 PLAN은 아래와 같이 나왔다.
Execution Plan
--------------------------------------------------------------------------------
0 SELECT STATEMENT Optimizer=ALL_ROWS (Cost=29 Card=1 Bytes=19)
1 0 TABLE ACCESS (FULL) OF 'EMPLOYEES' (TABLE) (Cost=29 Card=1 Bytes=19)
분명히 아래와 같은 INDEX를 생성하였다.
CREATE INDEX PK_EMP_ID ON EMPLOYEES(EMP_ID);
왜 인덱스를 안타는 것일까?
그 이유은 OPTIMIZER의 내부 변형 규칙에 있다.
일반적으로 비교를 하려면 두개의 데이터 형이 같아야 한다.
그런데 EMP_ID는 VARCHAR2(40)이다 그리고 비교하려는 것은 200383이라는 숫자이다.
따라서 숫자와 문자는 비교할수 없기 때문에 내부적으로 변형이 이루어진다.
문자보다 숫자가 우선순위가 높아서 문자와 숫자를 비교하게되면 문자쪽이 숫자로 변형되어 비교하게 되는 것이다.
따라서 위의 SQL은 OPTIMIZER는 아래와 같은 SQL로 수행하게된다.
EMP_ID를 TO_NUMBER(EMP_ID) = 2000393과 같이 처리하게 된다.
SELECT LAST_NAME,FIRST_NAME
FROM EMPLOYEES
WHERE TO_NUMBER(EMP_ID) = 200383;
이는 처음 예제에서 날짜 컬럼에 TO_CHAR를 씌원것과 같은 효과이다. 따라서 이문제를 해결하기위해서는 반대쪽, 즉 2000293을 문자로 변환해주면 문자대 문자의 비교이므로 내부적 변형이 발생하지 않게된다.
SELECT LAST_NAME,FIRST_NAME
FROM EMPLOYEES
WHERE EMP_ID = ‘200383’;
 
Execution Plan
--------------------------------------------------------------------------------
0 SELECT STATEMENT Optimizer=ALL_ROWS (Cost=2 Card=1 Bytes=19)
1 0 TABLE ACCESS (BY INDEX ROWID) OF 'EMPLOYEES' (TABLE) (Cost=2 Card=1 Bytes=19)
2 1 INDEX (RANGE SCAN) OF 'PK_EMP_ID' (INDEX) (Cost=1 Card=1)
아래 SQL을 보자 JOB에 NULL인 조건을 검색하는 것이다.
SELECT LAST_NAME,FIRST_NAME
FROM EMPLOYEES
WHERE JOB IS NULL
아래 SQL을 보자 JOB이 NULL인 조건을 검색하는 것이다.
물론 아래와 같은 JOB INDEX를 생성하였다.
CREATE INDEX IDX_JOB ON EMPLOYEES (JOB);
아래 PLAN을 보자 왜 IDX_JOB INDEX를 타지 못하는가?
Execution Plan
--------------------------------------------------------------------------------
0 SELECT STATEMENT Optimizer=ALL_ROWS (Cost=29 Card=3 Bytes=63)
1 0 TABLE ACCESS (FULL) OF 'EMPLOYEES' (TABLE) (Cost=29 Card=3 Bytes=63)
이경우에는 Oracle의 경우 일반적으로 index를 생성할 때 null값은 index항목에 넣지 않는다. 따라서 null은 index에 없기 때문에 null조건을 준다면 그것은 index를 탈수 없다.
따라서 위와 같은 경우 반드시 index를 타려거든 job컬럼을 NOT NULL로 설정하고 NUL대신 특정값 (예를 들면 : ‘NOT ASSIGN’ ) 으로 설정하고 QUERY를 아래와 같이 수정한다면 인덱스를 탈수 있을 것이다.
SELECT LAST_NAME,FIRST_NAME
FROM EMPLOYEES
WHERE JOB = ‘NOT ASSIGN’;
아래 SQL를 하나 더 보자
SELECT LAST_NAME,FIRST_NAME
FROM EMPLOYEES
WHERE JOB NOT IN ( 'INSTRUCTOR','STAFF');
이번의 NULL을 비교한것도 아닌데 INDEX를 사용하지 못한다. 이것은 일반적인 INDEX가 =이나 <, > , BETWEEN조건에 만 인덱스를 탈수 있고 부정형으로 비교했을때는 인덱스를 탈수 없기때문이다.
생각해보자 어떤 것을 순서대로 정리해 놓았는데 그것이 아닌 것을 찾으려고 한다면 전체를 다 읽어봐야지만 아니것을 알수 있지 않은가?
따라서 가급적 프로그램 구성에서 부정형 조건이 들어가게 한다는 것은 성능을 저하시킬 가능성이 매우 높기 때문에 이런 조건이 되지 않도록 설계단설계부터 고려해야한다.

이상은 간단하게 INDEX를 주었을 때 일반적으로 INDEX를 타지 못하는 경우를 든것이다. 사실 위예 예처럼 실제 프로젝트에서 많은 부분이 INDEX를 생성하고도 OPTIMIZER의 특성을 몰라서 INDEX를 쓰지 못한채 APPLICATION이 돌고 있다. 이는 곧바로 자원의 과도 사용으로 나타나고 느린 응답시간으로 나타나게 된다. 항상 시스템을 OPEN하고 마음을 조리지 않으려면 내가 생성된 INDEX를 잘 탈수 있게 내가 SQL을 잘 작성했는지 검토해 보기 바란다.
아래 4개의 항목은 반드시 기억해 두기 바란다.
인덱스를 사용하지 못하는 경우는 아래와 같다.
  • 인덱스 컬럼에 변형이 일어난 경우
    • WHERE TO_CHAR(HIREDATE,'YYYYMMDD') = '19980518';
    • WHERE SALARY + 1000 > 100000;
  • 내부적인 변형이 일어난 경우
    • WHERE EMP_ID = 200383;
  • NULL을 비교하였을 경우
    • WHERE JOB IS NULL;
  • 부정형으로 조건을 기술한 경우
    • WHERE JOB NOT IN ( 'INSTRUCTOR','STAFF');

물론 이 경우 이외에 Optimizer의 판단에 따라서 인덱스를 사용하지 못하는 경우도 있다. 그러나 대부분의 경우에는 위에 항목을 만족한다면 원하는 index를 타는 효율적인 sql작성에 좋은 기준이 될것이다. 마지막으로 sql을 작성한후 반드시 plan을 확인해 보기 바란다.
실제 plan이 어떻게 되는냐를 확인해보지 않으면 무심코 과거의 실수를 답습할 수 있기때문이다.


'데이터베이스' 카테고리의 다른 글

mysql 패스워드 분실시에  (0) 2014.04.04
오라클 scott 유저 활성화  (0) 2013.11.04
mysql 기본사용  (0) 2013.01.20
mysql 사용자 권한 넣기  (0) 2013.01.02
mysql 컬럼 수정 삭제 추가  (0) 2012.12.09
//
데이터베이스 2013. 1. 20. 22:15

//==================== 리눅스에서 sql파일 실행 =======================

] # mysql -h localhost -u root -D mChart -p < create_table.sql

//========================== DB 한글 깨짐 방지 =========================================

db접속후 케릭터 셋을 지정해준다.

<php 예>

$db = new mysqli('localhost','root','1234','myDB');
$db->query('set names euckr');

//=========================== 계정 비밀번호 변경 ==========================================

update mysql.user set password = password('암호') where user = '계정@localhost';
flush privileges;

//============================ 컬럼위치 변경 ==============================================

alter table 테이블명 modify 컬럼명1 타입 after 컬럼명2 // 컬럼1을 컬럼2뒤로 옮김;
예)
alter table myTable modify name varchar(10) aflter id;

//============================ 테이블 생성시 코멘트 달기 ==================================

create table customer_id_list

(

cust_id char(7) not null primary key comment '고객사ID',

cust_name varchar(30) not null comment '고객사명',

reg_date datetime not null comment '등록일'

)type=innodb,character set = utf8, comment = '고객사ID리스트';

//==================== 기본 명령 ====================================

mysql> create database dbName; // db 생성

예) create databases dbName default character set utf8 ;

mysql> drop database dbName; //db 삭제

mysql> create table tableNae(columns); //table 생성

예) create table books ( isbn char(13) not null primary key, //null값을 가질수 없는 기본키

author char(50),

title char(100),

price float(4,2) );

예) create table books ( isbn char(13) not null , //기본키가 여러개일때

author char(50) not null ,

title char(100),

price float(4,2),

primary key(isbn, author ) );

price float(4,2) );

예) create table books ( isbn char(13) not null , //테이블 collation 변경

author char(50) not null ,

title char(100) character set utf8 collate utf8_general_ci not null,

price float(4,2),

primary key(isbn, author ) );

예) create view cust_user_view as

select user.user_id, cust.cust_id, cust.cust_name,user.user_name

from cust,user

where cust.cust_id = user.cust_id ;

mysql> drop table tableName; //table 삭제

mysql> show databases [ like database ]; // 모든 사용할 수 있는 db 보여줌

mysql> show [ open ] tables [ from database ][ like table ]; // 선택된 DB의 모든 table 보여줌

mysql> show grants for user ; // user가 가진 권한을 설정하기위한 grant 문을 보여준다.

mysql> show create table db.table ; //테이블 생성 구조 보기

mysql> describe tableName [column]; //table의 구조를 보여줌

mysql> use dbName; // DB 사용 선택

//====== 사용자 및 권한 부여==================================================================

※ 모든 호스트 'id'@'%'

mysql> grant all //모든권한

-> on * // 모든 DB

-> to fred identified by 'mnb123' // 비밀번호 mnb123으로 접속하는 fred라는 사용자에게

-> with grant option; // 다른사용자에게 권한을 부여할 수도 있게

mysql> grant usage //권한없는

-> on books.* // books DB및 table에 대해서

-> to sally identified by 'mnb123' ; // 비밀번호 'magic123'으로 접속하는 sally라는 사용자에게

mysql> grant select, insert, update, delete, index, alter, create, drop // 해당 명령어 권한 부여

-> on books.* // books DB및 table에 대해서

-> to sally ; // sally라는 사용자에게

mysql> grant select, insert, update, delete // 해당 명령어 권한 부여

-> on books.* // books DB및 table에 대해서

->to sally@localhost identified by 'sally123' ; // sally@localhost 와 비밀번호로 접속하는 사용자에게

mysql> revoke alter, create, drop //해단 권한을 취소

-> on books.* // books DB및 table에 대해서

-> from sally; // sally라는 사용자의

mysql> revoke all // 모든 권한을 뺏어 해당 DB에 접근 하지 못하도록 한다.

-> on books.*

-> from sally;

mysql> use mysql; //계정 삭제

mysql> drop user sally@localhost ;

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

================== Select 문 ==================

select [ options ] items [ into file_details ]

from tables

[ where conditions ]

[ group by group_type ]

[ having where_definition ]

[ order by order_type ]

[ limit limit_criteria ]

[ procedure proc_name(arguments) ]

[ lock_options ]

;

예) custtomers 테이블에서 city 값이 seoul인 레코드의 name,city 값을 불러온다 5개만

select name, city

from customers

where city='seoul'

limit 5 ;

예) 현재 날자와의 차이 구하기 (D-Day)

select end_date,dateDIFF(end_date, now() ) as dday

from date_count

================== Insert 문 ==================

insert [ into ] tableName [(column1,column2,column3,...)] //table의 필드에 해당 값을 저장

values (value1, value2, value3,...) ;

예) insert customer_user

set customer = 'gmate',

user_name = 'gmate',

user_password = sha1('gmate');

예) insert customer_user values

( 'gmate', 'gmate', sha1('gmate')),

('ccr','user', sha1('gmate')) ;

예) insert 중 중복발생시 업데이트 하기

insert into user (id, name,age) values

('$id', '$name', 'age')

ON DUPLICATE KEY UPDATE

id='$id',

name ='$name',

age='$age';

================== delete 문 ==================

delete [ low_priority ] [ quick ] [ ignore ] from tableName //table의 레코드 삭제

[ where conditions ]

[ order by order_cols ]

[ limit number ]

예) delete from customer_user

where customer = 'gmate' ;

================== update 문 ==================

update [ low_priority ] [ ignore ] tableName //table의 레코드 수정

set column1=expression1, column2=expression2,...

[ where conditions ]

[ order by order_criteria ]

[ limit number ]

예) update customer

set customer_name='성재욱'

where customer_id ='aaa';

================== alter table문 ==================

alter table tableName add fieldName varchar(10) not null ;

예) alter table myTable add name varchar(30) not null;

//-----필드 삭제

alter table tableName drop fieldName ;l

//-----엔진타입 변경

alter table tableName ENGINE = innoDB ;

alter table tableName ENGINE = MYISAM ;

============= 외래키(foreign key) 생성 ====================================================

# 테이블 타입이 innoDB 이어야 적용된다(부모자식 테이블 모두).

create table board_10001 (

postid int(10) unsigned not null auto_increment primary key,

sub_code char(4) not null ,

title varchar(40) not null,

contents text not null,

date timestamp ,

writer char(10) not null ,

foreign key(sub_code) references board_sub_list(sub_code),

foreign key(writer) references user(user_id)

)type=innodb , character set = utf8;

============= 테이블에 외래키 추가수정 ===========================================

alter table board_10002

add constraint foreign key(sub_code) references board_sub_list(sub_code);

=================== 외래키 옵션 ===========================================================

CASCADE
참조되는 측 관계 변수의 행이 삭제 되었을 경우에는 참조하는 측 관계 병수와 대응되는 모든 행들이 삭제 됩니다 . 참조되는 측 관계 변수의 행이 갱신 되었을 경우에는 참조하는 측 관계 변수의 외래 키 값은 같은 값으로 갱신됩니다.
예)

foreign key(id) references customer_info(id) ON DELETE CASCADE ON UPDATE CASCADE

RESTRICT
참조하는 측 관계 변수의 행이 남아 있는 경우에는 참조되는 측의행을 갱신하거나 삭제 할 수 없습니다. 이 경우에는 데이터 변경이 이루어 지지 않습니다.

NO ACTION
참조되는 측 관계변수에 대해 UPDATE, DELETE 가 실행됩니다. DBMS에서 SQL문장의 실행 종료시에 참조 정합성을 만족하는지 검사합니다. RESTRICT와 차이점은 트리거 또는 SQL문장의 시멘틱스 자체가 외래키의 제약을 채울것이라는 데에 있습니다. 이때는 SQL 문장 실행이 성공합니다. 외래 키의 제약이 만족되지 않은 경우에는 SQL문장이 실패한다.

SET NULL
참조되는 측 관계 변수에 대해 행이 갱신 또는 삭제 되었을 경우 , 참조하는 측 관계 변수의 행에 대한 외래키 값은 NULL로 설정이 됩니다. 이 옵션은 참조하는 측 관계 변수의 외래 키에 NULL 을 설정할 수 있는 경우에만 가능합니다. NULL 의 시멘틱스에 의해 참조하는 측 관계 변수에 대해 NULL이 있는 행은 , 참조 되는 측 관계 변수의 행을 필요로 하지 않습니다.

SET DEFAULT
SET NULL 과 비슷하지만 참조되는 측 관계 변수의 행이 갱신 또는 삭제 되었을 경우 참조하는 측 관계 변수의 외래키 값은 속성의 기본값으로 설정됩니다.

위와 같은 5개의 참조 조작이 SQL:2003에 규정되어 있습니다.

MySQL 에서는 InnoDB 에서 지원을 합니다. 지원하는 참조 조작은 RESTRICT, CASCADE, SET NULL, NO ACTION 을 지원합니다

====================== 뷰(view) 테이블 생성 ============================================

create view cust_user_view as

select user.user_id, customer.customer_id, customer.customer_name,user.user_name

from customer,user

where customer.customer_id = user.customer_id ;

'데이터베이스' 카테고리의 다른 글

mysql 패스워드 분실시에  (0) 2014.04.04
오라클 scott 유저 활성화  (0) 2013.11.04
DB index 사용하기  (0) 2013.10.15
mysql 사용자 권한 넣기  (0) 2013.01.02
mysql 컬럼 수정 삭제 추가  (0) 2012.12.09
//
데이터베이스 2013. 1. 2. 01:51

grant all privileges on [데이터베이스명].* to '[사용자계정]'@'[호스트ip]' identified by '[계정패스워드]';

'데이터베이스' 카테고리의 다른 글

mysql 패스워드 분실시에  (0) 2014.04.04
오라클 scott 유저 활성화  (0) 2013.11.04
DB index 사용하기  (0) 2013.10.15
mysql 기본사용  (0) 2013.01.20
mysql 컬럼 수정 삭제 추가  (0) 2012.12.09
//
데이터베이스 2012. 12. 9. 13:54

1. 컬럼명 변경&타입 변경

alter table 테이블명 change 기존컬럼명 변경할컬럼명 컬럼타입;

ex)   alter table tb_test change guide guide_img varchar(500);

 

2. 컬럼 추가

alter table 테이블명 add 추가할컬럼명 컬럼타입 칼럼위치 디폴;  

ex) alter table co_test add tpaper_seq int(11) after seq defalut '0';

 

3. 컬럼 삭제

alter table 테이블명 drop 삭제할컬럼명;

ex) alter table co_test drop grade;

'데이터베이스' 카테고리의 다른 글

mysql 패스워드 분실시에  (0) 2014.04.04
오라클 scott 유저 활성화  (0) 2013.11.04
DB index 사용하기  (0) 2013.10.15
mysql 기본사용  (0) 2013.01.20
mysql 사용자 권한 넣기  (0) 2013.01.02
//