제1정규화
 제1정규형의 정의는 테이블 셀에 복합적인값을 포함하지않는다 (스칼라값만을 갖음), 그러나 배열을 insert 할 수 없기때문에 제 1정규형은 자동으로만족한다.

제2정규화 (2NF)
 부분함수의 종속성 = 기본키를 구성하는 열의 일부에만 종속성을 갖음 (복합키일경우) 예를들어 table 회사별 주문에 회사id+주문번호가 키값이라 쳐보자 
 create table 회사별 주문 {
  회사id ,
  주문번호,
  주문일자,
  회사이름,
  고객기업규모,
  PRIMARY KEY(회사id,주문번호)

 위 테이블은 제2정규형을 만족하지 못함, 회사id에만 종속되는게 존재, 회사이름 및 고객기업규모 만 종속됨. 이게 왜 위험하냐면, 주문을 했을때 주문을 한 정보만으로는 고객기업규모를 알아낼수 없음, 이럴경우 NULL을 허가하거나 더미값추가? => 이런 갱신시 부정합을 갱신이상이라함.

제3정규화 (3NF)
 추이함수의 종속이 없어야한다. 다음과같은 테이블이 있다고 가정하자. 
 create table 회사 {
 회사ID,
 회사명,
 규모,
 업계코드,
 업계명,
 PRIMARY KEY (회사ID)

 2NF까진 만족하는듯 하다. 그러나 추이함수의 종속성을 갖는다. (2단계의 함수종속성)  
현재 (회사ID->업계코드->업계명) 이런식으로 종속되어있다. 이럴경우 새로운 업계를 추가할 수 있을까? 업계코드에 따른 업계명은 다른 테이블을 빼야한다.

 

 

지난글 에서는 Transaction이 무엇인지에 대해서 한번 살펴보았다.
이번에는 지난번에 설명했던 ANSI에서 정의한 Transaction의 Isolation level 4단계에대해서 알아보자.

 

격리레벨 4단계를 이해하기위해 일단 상황을 가정해보자. 
 Table USER는 id와 name column이 있다.
 그리고 동시에 실행되는 processes a, b, c 가 있다고 가정해보자 a는 트렌젝션을 시작하고, 이것은 data를 insert하는데 commit될수도 있고, 커밋이 안될 수 도 있다. b는 SELECT 쿼리를 2번 사용하는 트랜잭션이다. c는 data를 select하고 update 한다. 이 모든 프로세스는 USER Table에서 실행된다고 가정하자.

 

READ UNCOMMITTED 
* b = (select * from user);
 이 레벨은 table에 락을 걸지 않는다. 이 말인즉슨 A가 USER table에 {id:user10,name:홍길동}을 insert하는 도중에 (권한 처리를 위해  아직 uncomitted되었다.)  B가 SELECT를 한다면 이 Uncommitted 되는 {id:user10,name:홍길동}을 본다는  이야기이다.(Dirty Read) 심지어 a가 rollback 되었음에도 B의 SELECT 결과 에는 사용된다. 이는 가장 빠르긴하지만, 안전하지않다. 

 

READ COMMITTED
 * b = (select * from user where id='user10');
 이 레벨에서는 커밋된 데이터에 락을건다. 커밋된 데이터만 읽을수 있지만, c가 만약 트랜젝션중간에 update를 하고 commit을 하면, b가 1회에 select한 데이터가 2회에는 달라질수가 있다(Non repeatable read). 예를들어보자. b 트랜젝션에서 {id:user10, name:홍길동} 데이터를 1회 읽었다. 그런데 c transaction에서 user10의 이름을 '김길동'이라고 바꿨다. 다시 b에서 2회 select를 실행했을땐 {id:user10, name:홍길동} 을 읽게된다.

REPEATABLE READ
 * b = (select * from user where name='홍길동');
 이 레벨에서는 block of SQL의 lock을 건다. 만약 현재 USER TABLE에 {user:aaa,name:홍길동}, {user:bbb,name:홍길동}이 있다고 가정하자. 그런데 a 트랜잭션에서 도중에 {user:ccc, name:홍길동}을 넣고 commit 했다. 그리고나서 b가 2회째 select를 수행하게되면 1회째와 달리 총 3개의 행을 select 하게된다.(Phantom read)

 

SERIALIZABLE
 이 레벨은 전체 테이블을 잠근다(위의 예제는 b가 select를 2번 실행할동안 table 전체를 lock 한다.) 이것은 가장 안전하지만, 비효율적이고 가장 느린데이터 작업방법이다. 

 


위의 내용들 참고하여 transaction isolation level에 따른 나타날수 있는 현상을 정리하자면 다음과 같다.

  Dirty Read Non repeatable read Phantom read
READ UNCOMMITTED 
Permitted Permitted Permitted
READ COMMITTED
x Permitted Permitted
REPEATABLE READ
x x Permitted
SERIALIZABLE
x x x

 

출처
https://stackoverflow.com/questions/16162357/transaction-isolation-levels-relation-with-locks-on-table

https://stackoverflow.com/questions/11043712/what-is-the-difference-between-non-repeatable-read-and-phantom-read

트랜잭션이란 

- 복수 쿼리를 한 단위로 묶은 것
- 한 덩어리의 쿼리 처리 단위
- 일반적인 DBMS에서 어플리케이션 로직을 구성할 때 사용


Atomicity
- 데이터의 갱신(insery / delete / update)을 수반하는 데이터 조작이 전부 성공할지 전부 실패할지 보증하는 것
- 하나의 트랜잭션이 부분적으로 실행되다가 중단되지 않는 것을 보장
- 예를들어 돈을 빼 오는 작업만 성공하고 받는 쪽에 돈을 넣는 작업을 실패해서는 안됨.

Consistency (일관성)
- 트랜잭션이 실행을 성공적으로 완료하면 일관성있는 데이터베이스의 상태를 유지해야함.
- 무결성 제약중 NOT NULL 조건이있다면 트랜젝션은 중단되어야한다.

Isolation
- 트랜잭션 연산시 다른연산이 끼어들지 못하도록 보장.
- 예를들어 A와 B가 호텔예약을 한다고 했을때, select 후 insert를 하는 트랜잭션을 생각해보자,  A가 트랜잭션을 위해 select 방;을 했을때 10개 빈방이 존재한다면, A가 트랜잭션을 수행하는도중 B가 트랜잭션을 수행하여 select 방; 을똑같이하면 빈방은 10개여야할까? 9개여야할까? mysql 같은경우는 락을걸어 이런 isolation을 보장한다.
- 즉, 고립성이란 복수의 트랜잭션이 순서대로 실행되는것이며 이는 데이터가 병렬로 처리되는 것이 아닌, 직렬로 처리되는 것을 말함. 이는 Serializable(직렬화 가능)한 고립성이라고 함
- 그러나 직렬화로 인해 동시에 동작하는 Transaction이 1가지일경우 성능면에서 비효율적이다.
- ANSI(미국국가규격협회) 에서 권고하는 트랜젝션 격리 완화수준 4개가 있다. 이를 트랜젝션의 격리수준(Transaction Isolationo Level) 이라 한다.

Durability
-성공적으로 실행된 트랜잭션은 persistance 하게 반영되여야함. 즉 시스템 장애, DB일관성 체크등을 하더라도 유지되어야함.
-트랜잭션은 로그에 모든것이 저장된우 Commit으로 간주됨


0. 

윈도우 10을 깔고, 개발환경을 구축하고 있습니다.

이곳저곳 기웃거리며 mysql 수동설치를 찾는데, 16/02/11기준 mysql 최신 버전이라 그런것인지 설치 방법이 조금씩 달랐습니다.

에러들을 처리하고 나서 정리하는 겸 적습니다.


1. 

http://dev.mysql.com/downloads/mysql/

에서 mysql-5.7.10-winx64을 다운

(Windows 10 64 bit을 사용할 경우)




2.

다운 후 원하는 경로에 압축풀기.

전 d:\mysql에 풀었습니다.

폴더 안에 my-default.ini 를 열고 수정합니다.

아래처럼 수정하시고 my.ini로 같은 폴더에 "다른이름으로 저장" 해주세요.

 1) basedir, datadir, port 앞에 주석(#)을 삭제한다.

 2) basedir에는 mysql 압축을 푼 폴더를 작성. (폴더경로는 백슬래시(\)가 아닌 슬래시로(/)

 3) datadir은 mysql압축을 푼 폴더 안에 data폴더

 4) port를 3306

 5) 수정 후, 다른 이름으로 저장 .. 이름을 my.ini로 같은 폴더에 저장합니다.

=>결과



3.

제어판에 환경변수에서 mysql 환경 변수를 등록해줍시다. 윈도우 키 누르시고 환경변수 검색하시면 바로 찾으실 수 있습니다.

전 설치한 경로가 d:\mysql이므로 MYSQL_HOME을 그곳으로 등록하였습니다.




이후, Path에 MYSQL_HOME\bin 폴더를 추가해줍니다.

%MYSQL_HOME%\bin 으로 적어야 합니다. MYSQL_HOME 양 옆에 %를 붙여주세요.

bin 전에는 \넣어주세요.





4.

 관리자 권한으로 명령 프롬프트를 실행합니다.

윈도우 키 누르시고 명령 프롬프트 검색 후 오른쪽 클릭, 관리자 권한으로 실행 혹은

윈도우 + x 키를 누르고 명령 프롬프트(관리자)를 찾으실 수 있습니다.


실행하시고 mysqld --initialize 를 입력


끝나고 명령 프롬프트엔 아무것도 안 나옵니다.

d:\mysql\data 폴더에(my.ini에 datadir로 입력하신 폴더) 데이터가 들어가는 것을 보실 수 있습니다.

(도중 문제가 생기셨다면, data 폴더 안에 내용을 비우고 다시 mysql --initialize 합니다.)


5.

 mysql을 서비스에 등록

"mysql 경로\bin\mysqld" --install

"d:\mysql\bin\mysqld" --install

(혹시나 안되시면, mysqld.exe로 

"d:\mysql\bin\mysqld.exe" --install)

=>path를 등록하였기 때문에 mysqld --install해도 서비스는 등록되지만, 실행하시면 에러가 발생합니다.

서비스 경로가 c드라이브의 mysql이 설치되는 기본 폴더로 지정되있게 되고, 이를 찾지 못해서 에러가 발생합니다.

=>삭제는 --remove입니다.


등록에 성공하였으면, 서비스를 시작해봅시다.

서비스 시작은 꼭 명령 프롬프트가 관리자 권한으로 실행되어야 합니다.

net start mysql

=> 서비스 중지는 net stop mysql


6.

서비스가 잘 시작되면, 루트 계정으로 접속해봅니다.

mysql -u root -p

그럼 또 에러가 납니다.

이유는 잘 모르겠지만, root의 비밀번호가 다르다고 접속할 수 없습니다. 지정한 적 없다 이놈아.

그래서 root의 비밀번호를 바꿔주어야 합니다.

일단, mysql에 root로 비밀번호가 없더라도 접속할 수 있어야 합니다.


 1)

 관리자 권한 명령 프롬프트로, 서비스를 멈춥시다.

 net stop mysql


 2)

 비밀번호를 생략하도록 서비스를 다시 시작합시다.

 mysqld --skip-grant-tables

 입력하면, 해당 명령 프롬프트는 서비스를 실행하느라 사용할 수 없습니다.


 3)

 다른 명령 프롬프트를 열고, mysql에 접속합니다.

 (새로 연 명령 프롬프트)

 mysql -u root -p

 비밀번호 입력하는데 엔터 눌러도 접속됩니다.


 4)

 use mysql;

 update user set authentication_string = password('새로운 비밀번호') where user = 'root'; 

 flush privileges;


 5)

 비밀번호를 생략했던 서버를 종료시키고, 새로운 비밀번호로 접속해봅시다.

 mysqld --skip-grant-tables 를 실행했던 명령 프롬프트를 종료합시다.

 윈도우키 + x 를 눌러 작업관리자(T)를 실행시키고, 백그라운드 프로세스에 있는 mysqld.exe를 종료시킵니다.


 6)

 명령 프롬프트를 관리자 권한으로 실행시키고, mysql 서비스를 시작합니다.

 net start mysql


 7)

 mysql -u root -p

 를 입력하고,

 새로운 비밀번호를 입력하면 접속할 수 있습니다.

 다만 사용하려면 root 비밀번호를 다시 설정하라는 알림이 뜹니다.

 alter user 'root'@'localhost' identified by '새로운 비밀번호';

 를 다시 입력해주셔야 정상적으로 사용 가능합니다.


7. 마치며

제가 한 방법이 정석이 아닐 수 있습니다. 전 제가 헤맨 과정을 그대로 적었습니다. 더 좋은 방법이 있다면, 댓글로 달아주시면 감사하겠습니다.

설치를 완료한 후 기억에 의존하여 적은 것이라, 혹시나 잘못된 점이 있다면 댓글 부탁드립니다.




+추가 database 와 datebase 내의 테이블은 다르므로 

그냥 root 계정내의 테이블을 추가해줬음

구지 new 계정을 추가하고 권한을 부여하고싶다면

http://ourcstory.tistory.com/45

여기서 권한부여 하면됨


+추가

차셋이 

mysql 내에서 

show variables like 'char%' 로 보면

euc-kr 이라서 utf-8 이안들어감 근데 my.ini 파일에서 수정하면 된다는데 때려 죽여도 못찾겠음.

https://stackoverflow.com/questions/22572558/how-to-set-character-set-database-and-collation-database-to-utf8-in-my-ini


이걸 참고해서 데이터베이스 별로 utf-8로 바꿔줄수있음 



추신

원본출처 : http://bombay.tistory.com/3



문자열 간의 최단거리 찾기
 

***Scenario:데이터 활용시 사람간의 매칭 기능을 만드려고 참고한 내용

(주관식 설문지를 작성할경우) 예를들어 혈액형을 입력하라고 하자.
A임, A형,  A형임,

이 3답변은 실질적으로 같은답변이지만 단순히 Like 를 사용해서 쿼리를 작성할경우 찾을 수 가 없다.

그렇다면 어떻게 하면 3개의 답변이 비슷하다고 가정 할 수있을까?? 원래는 DAO에서 모든 데이터를 불러온다음 자료구좋에 넣어 파싱을 해서 검색을 하려고했다.

그러나 오버헤드가 너무 클 것같았다. 고민하던중 다음과 같은 포스팅을 찾을 수있엇다


두 개의 문자열 사이에 유사도가 가까울수록 같은 계열의 값으로 판단할 수 있을것이다.

이러한 기능을 수행하려면 모든 데이터 값들간의 조인이 일어나야하는데 사용자 정의 함수를 사용하면

최적화 되지 않는 경우가 많기 때문에 프로젝트에서 결과값을 얻기 쉽지가 않다.

Oracle 11g에서의 new feature가 있는데 아주 유용한 기능으로 소개하기로 한다.

DROP TABLE match_tab;

CREATE TABLE match_tab (
  id   NUMBER,
  col1 VARCHAR2(50),
  col2 VARCHAR2(50),
  CONSTRAINT match_tab_pk PRIMARY  KEY (id)
);

INSERT INTO match_tab VALUES (1, 'Peter Parker', 'Pete Parker');
INSERT INTO match_tab VALUES (2, 'Peter Parker', 'peter parker');
INSERT INTO match_tab VALUES (3, 'Clark Kent', 'Claire Kent');
INSERT INTO match_tab VALUES (4, 'Wonder Woman', 'Ponder Woman');
INSERT INTO match_tab VALUES (5, 'Superman', 'Superman');
INSERT INTO match_tab VALUES (6, 'The Hulk', 'Iron Man');

INSERT INTO match_tab VALUES (11, '환자입원일시', '환자입원일');
INSERT INTO match_tab VALUES (12, '슈퍼맨', '슈퍼 맨');
INSERT INTO match_tab VALUES (13, '슈퍼맨', '슈퍼맨');
INSERT INTO match_tab VALUES (14, '슈퍼맨', '아이언맨');
INSERT INTO match_tab VALUES (15, '동창생', '도차생');
INSERT INTO match_tab VALUES (16, '일반 환자 격리', '일반환자격리');
INSERT INTO match_tab VALUES (17, '트러블 메 이 커', '트메이크');

COMMIT;

SELECT col1,
       col2,
       UTL_MATCH.edit_distance(col1, col2) AS ed,
       UTL_MATCH.edit_distance_similarity(col1, col2) AS eds,
       UTL_MATCH.jaro_winkler(col1, col2) AS jw,
       UTL_MATCH.jaro_winkler_similarity(col1, col2) AS jws
FROM   COMP_TABLE
ORDER BY id;

우리가 눈여겨 볼만한것은 유사도입니다. EDS, JWS

영문과 한글일때의 유사도의 차이는 조금 다르지만 문자열에 대한 유사도를 찾을수 있는

좋은 기능입니다.

잘만 응용하면 좋은 TIP이 될수 있을것입니다.


출처:http://www.dator.co.kr/newyemac/894089


Scenario: 이번 프로젝트를 할때 설문조사를 실행하여 사람과 사람간의 유사한답변을 찾은사람끼리 매칭시켜주는 기능을 만들고자 했었다.


Solutions: 맨처음에는 주관식을 하여 단어간의 유사성을 찾아 매칭시켜줄려고 했지만, 객관식으로 하는것이 더 깔끔 할 것같아서 바꿈


1.테이블 구조(간단함)

SQL 0.19 KB
  1. CREATE TABLE MBER_TQ
  2. (  
  3.     TQ_IDX         NUMBER  PRIMARY KEY,
  4.     MBER_EMAIL      varchar2(50) NULL,
  5.     TQ_QUESTION     NUMBER NULL,
  6.     TQ_ANSWER       NUMBER NULL,
  7.   DEL_FLAG varchar2(5) DEFAULT 'N'
  8. );


2.설문조사를 시작하자마자 수행되는 쿼리

SQL 0.63 KB
  1. --같은사용자가 재 설문조사를할경우 Init해주는 쿼리(시작하기전에 한번 실행)
  2. UPDATE MBER_TQ
  3. SET DEL_FLAG = 'Y'
  4. WHERE MBER_EMAIL = '1@gmail.com';
  5.  
  6.  
  7. --답변을 선택할때마다 동적으로 실행되는 인서트쿼리
  8. INSERT INTO MBER_TQ VALUES(SEQ_MBER_TQ_IDX.NEXTVAL ,'97@gmail.com' ,1,2,'N');
  9. INSERT INTO MBER_TQ VALUES(SEQ_MBER_TQ_IDX.NEXTVAL ,'98@gmail.com' ,1,1,'N');
  10. INSERT INTO MBER_TQ VALUES(SEQ_MBER_TQ_IDX.NEXTVAL ,'99@gmail.com' ,1,3,'N');
  11. INSERT INTO MBER_TQ VALUES(SEQ_MBER_TQ_IDX.NEXTVAL ,'100@gmail.com' ,1,4,'N');
  12. INSERT INTO MBER_TQ VALUES(SEQ_MBER_TQ_IDX.NEXTVAL ,'101@gmail.com' ,1,2,'N');



3.핵심쿼리(내가 선택한 답변을 db에서 다른사람이 선택한 답변과 비교하여 상위 4명을 잘라서 보여줌)

SQL 0.77 KB
  1. SELECT MBER_NAME, MBER_IMG, MBER_INFO_IDX, MBER_SKILL, MBER_INTRODUCE, MI.MBER_EMAIL, SCORE
  2. FROM(SELECT MBER_EMAIL, SCORE
  3.      FROM  
  4.       (SELECT A.MBER_EMAIL ,SUM(B.SCORE) AS SCORE
  5.        FROM MBER_TQ A JOIN
  6.         (SELECT  MBER_EMAIL, TQ_QUESTION, TQ_ANSWER, 1 SCORE
  7.          FROM MBER_TQ
  8.          WHERE MBER_EMAIL='a@GMAIL.COM'
  9.          AND DEL_FLAG != 'Y') B
  10.        ON A.TQ_QUESTION = B.TQ_QUESTION
  11.        AND A.TQ_ANSWER = B.TQ_ANSWER
  12.        AND A.MBER_EMAIL != 'a@GMAIL.COM'
  13.        AND DEL_FLAG != 'Y'
  14.        AND SCORE IS NOT NULL
  15.        GROUP BY A.MBER_EMAIL
  16.        ORDER BY SUM(B.SCORE) DESC)
  17.        WHERE ROWNUM <= 4) GENIE, MBER_INFO MI ,MBER
  18. WHERE GENIE.MBER_EMAIL = MI.MBER_EMAIL
  19. AND MBER.MBER_EMAIL = MI.MBER_EMAIL
  20. ORDER BY GENIE.SCORE DESC;


scenario: 오픈소스를 분석하다가 erwin으로 DB에 테이블 생성을 했는데 삑사리가 나서 테이블이 꼬여버렸다. , 그래서 사용자내 모든 DB를 삭제하고 다시 만들고자 하였음.


solutions:(아래)


begin

for c in(select table_name from user_tables)loop

execute immediate('drop table '||c.table_name||' cascade constraints');

end loop;

end;

purge recyclebin;


select table_name from user_tables;


ps. 계정아이디 같은거 안넣어줘도 된다. 처음에 소스를 분석해보는데 (PL/SQL을 잘모름) 왜 계정이름 넣는 칸이없지?? 하고 고민함.


('drop table '||c.table_name||' cascade constraints'); 이 구문에서 띄어쓰기 조심할것, 오타율 심하면 그냥 복붙해서 사용할 것.



Scenario:강의들을 동안은 권한주기 및 계정생성은 한번 밖에 안해봐서, 

어느날 새로운 계정으로 들어가 테이블들을 따로 관리하려니까 SQLDEVELOPER ID가 유효하지 않다고 하더라.


이유를 생각해보니 계정 생성및 grant 도 안해줘서 그런거였다. 이런 건 그냥 스크랩 해 두는 게 좋겠다.


solution:


Bash 0.96 KB
  1. Administrator@WIN-UB18TI2GOTU MINGW64 /
  2. $ sqlplus system/oracle
  3.  
  4. SQL*Plus: Release 11.2.0.2.0 Production on ±Ý 1¿ù 6 11:35:51 2017
  5.  
  6. Copyright (c) 19822014, Oracle.  All rights reserved.
  7.  
  8.  
  9. Connected to:
  10. Oracle Database 11g Express Edition Release 11.2.0.2.0 - 64bit Production
  11.  
  12. SQL> create user itcenter identified by java;
  13.  
  14. User created.
  15.  
  16. SQL> grant connect, resource to itcenter;
  17.  
  18. Grant succeeded.
  19.  
  20. SQL> exit
  21. Disconnected from Oracle Database 11g Express Edition Release 11.2.0.2.0 - 64bit Production
  22.  
  23.  
  24.  
  25.  
  26. /////////추가로 필요 명령어들/////////////
  27. SQL> SHOW USER;
  28. SQL>SELECT * FROM all_users;
  29. //다른 계정으로 넘어가기
  30. SQL>conn testuser/testuser;
  31. //유저 비밀번호생성
  32. SQL>ALTER USER testuser IDENTIFIED BY "chagepwd";
  33. //유저 삭제
  34. SQL>DROP USER testuser;
  35.  
  36. //유저명 변경은 어렵다고하니 다음에 알아보도록 하자 -_-;;
  37.  
  38. //유저 비밀번호 변경
  39. SQL>alter user scott identified by scott;


+ Recent posts