DB의 쿼리 수행 속도 저하의 문제 중 하나는 쿼리 튜닝이 문제일 수도 있지만, 인덱스의 밸런스가 깨졌을 경우의 가능성도 있다. 인덱스 밸런스가 깨졌다는게 무슨 의미냐 하면, DB는 ArrayList와 트리를 합쳐 놓은 구조와 비슷한 B+트리 구조인데, 트리 아래의 데이터들이 무작위로 수정되거나 삭제 되었을 경우 트리 구조가 불균형을 이루게 된다.
이런 경우 인덱스를 재구성 해주면 쿼리 수행 속도를 향상 시킬 수 있다. (물론 튜닝이 잘 된 쿼리를 짜는게 중요하다.)
오라클의 인덱스 재설정 쿼리는 ALTER INDEX 인덱스명 REBUILD;이고, 인덱스 명을 조회하는 쿼리는 SELECT INDEX_NAME FROM USER_INDEXED;이다. 그리고 인덱스의 데이터 타입이 LOB이라면 인덱스 리빌드는 불가능 하다.
따라서 이 두 쿼리를 조합하고, 조건을 추가하면 리빌드 하는 쿼리는 다음과 같다.
SELECT 'ALTER INDEX ' || INDEX_NAME || ' REBUILD ;'
FROM USER_INDEXES
WHERE INDEX_TYPE != 'LOB'
;
대부분의 서버는 보안 문제로 ssh나 http, telnet 을 사용할 수 없는 경우가 있다.
이런 경우에 대상 버의 포트가 열려 있는지 확인 하는 방법에 대해서 삽질하다, 잊으면 안될것 같아서 남겨본다.
Linux의 경우이다.
echo > /dev/tcp/IP/PORT
bash의 내장 기능으로 자세한 내용은 여기 에서 확인 할 수 있다. 포트가 열린 경우라면, 아무 메세지가 나오지 않는다. echo $? 해보면 정상적인 프로세스의 종료를 의미하는 0이 나온다. 포트가 닫힌 경우라면, 에러메세지가 나오고 echo $?의 결과가 1이 나온다.
#include <stdio.h>
#include <stdlib.h>
void main()
{
int size;
char *a;
printf("입력할 문자열의 크기? : ");
scanf("%d", &size);
// 메모리 동적할당.
a = (char *)malloc(sizeof(char) * size);
printf("주소 : ");
scanf("%s", a);
printf("입력된 주소 %s\n", a);
free(a);
}
메모리 동적할당 함수
malloc(), calloc(), realloc(), free() 등
메모리 동적할당의 장/단점
힙 영역을 이용하여 프로그램 실행 중에 입력되는 자료의 크기에 맞게 기억 공간 확보.
많은 자료를 처리하는 배열의 크기를 실행 시간에 정의해야 하는 경우에 유용.
프로그램 실행 시 기억 공간의 크기를 지정/재조정 가능.
시간이 지체되는 단점.
메모리 동적할당 순서
기억공간을 동적으로 할당 받을 변수를 포인터를 이용하여 선언.
malloc() 등을 이용하여 기억공간을 동적으로 할당 가능.
기억공간의 사용이 끝나면 free()를 이용하여 기억공간 해제.
malloc()
인자로 할당 받고자 하는 기억 공간의 크기를 byte 단위로 전달.
힙 영역에 그 크기만큼 기억 공간을 할당, 할당한 기억공간의 첫 번째 주소 반환.
void*로 명시하여 어떤 형이든 형 변환 가능.
초기화 안됨(기억공간의 초기화를 위해서는 memset() 사용).
형식 : void * malloc(size_t, number_of_bytes);
기능 : number_of_bytes에서 주어지는 크기만큼 기억 공간을 동적으로 할당.
예 : void * malloc(sizeof(int));
free()
메모리 해제 함수.
힙 영역에 할당된 공간은 프로그램이 종료될 때까지 유지됨.
할당된 기억 공간을 해제하지 않으면, 공간 부족 현상 발생.
명시적인 반남.
형식 : void free(void *p);
기능 : 동적으로 할당된 기억 공간을 해제할 때 사용.
메모리 동적할당 예 - 1
#include <stdio.h>
#include <stdlib.h>
void main()
{
// 1) 동적할당을 위한 포인터변수 선언.
int *a;
// 2) 기억공간 할당,
// - (int *)는 왼쪽의 포인터변수 a와 자료형을 일치시키기 위한
// 강제 형변환.
a = (int *)malloc(sizeof(int));
if (a == NULL)
{
puts("FAILLURE OF ALLOCATION!");
exit(1);
}
*a = 20;
printf("VARIABLE a : %d\n", *a);
// 3) 할당받은 기억공간 해제.
free(a);
}
메모리 동적할당 예 - 2
#include <stdio.h>
#include <stdlib.h>
#pragma warning(disable : 4996)
void main()
{
// 입력받을 문자 수 저장 변수 선언.
int size;
// 1) 동적 할당된 기억공간을 연결할 포인터.
char *str;
printf("INSERT SIZE OF STRING : ");
scanf("%d", &size);
// 2) 입력 받을 문자 수(size + 1)에 맞게 동적 할당.
str = (char *)malloc(size + 1);
if (str == NULL)
{
puts("FAILLURE OF ALLOCATION!");
exit(1);
}
printf("INSERT STRING : ");
// 동적으로 할당된 기억공간에 문자열 저장.
scanf("%s", str);
printf("STRING THAT SAVED AT DYNAMIC MEMORY : \n%s\n", str);
// 3) 할당받은 기억공간 해제.
free(str);
}
calloc()
malloc()와 동일하게 힙 영역에 기억공간 할당.
사용하는 형태와 할당된 기억 공간을 0으로 초기화.
형식 : void * calloc( int n, int size );
기능 : 주어진 size의 크기를 갖는 기억 공간 n개를 할당.
예 : void * calloc( n, sizeof(int));
#include <stdio.h>
#include <stdlib.h>
void main()
{
int i;
int *a;
// int형 크기의 기억공간 5개 할당.
a = (int *)calloc(5, sizeof(int));
for (i = 0; i < 5; i++)
{
// 0으로 초기화 되어 있음.
printf("%d\n", a[i]);
}
free(a);
}
realloc()
이미 할당 받은 기억 공간의 크기를 변경해야 할 필요가 있을 때 사용.
형식 : void * realloc( void *p, int size);
기능 : 포인터 p가 가리키고 있는 기억공간의 크기를 지정된 size의 크기로 변경.
int *a;
// int형 크기의 5개 기억공간 할당.
a = (int *)calloc(5, sizefo(int));
...
// int형 크기의 10개 기억공간 재할당.
a = (int *) realloc(a, 10 * sizeof(int));
기억공간 관리함수
memcmp(), memcpy(), memset()
memcmp()
기억 공간에 들어 있는 자료를 주어지는 크기만큼 비교하여, 같은지 여부를 알 수 있게 해주는 함수.
#include <stdio.h>
#include <stdlib.h>
void main()
{
// 파일 포인터 선언
FILE *fp;
char c;
// 파일 생성이므로 텍스트 쓰기모드로 오픈.
fp = fopen("putc.tt.txt", "w");
// 파일 개방 여부 체크. -> 에러메세지와 프로그램 종료.
if (fp == NULL)
{
printf("FAIL TO OPEN FILE");
exit(1);
}
// 문자 출력의 끝 확인.
while ((c = getchar()) != EOF)
{
// 문자를 파일로 출력.
putc(c, fp);
}
printf("END OF WHILE!");
fclose(fp);
}
fputs()
문자열을 파일로 출력.
형식 : fputs(문자열변수, 파일포인터변수);
사용 예 : fputs(s, fp);
기능 : 지정된 파일에 문자열(하나의 레코드) 출력.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void main() {
char name[64];
FILE *fp;
// 텍스트 쓰기모드 개방하고, 에러시 프로그램 종료.
if ((fp = fopen("02_fputs.tt.txt", "w")) == NULL) {
puts("CAN NOT OPEN FILE");
exit(1);
}
gets(name);
while (strcmp(name, "end")) {
// 하나의 문자열에 개행문자 추가.
strcat(name, "\n");
// 문자열을 fp가 가르키는 파일에 수록.
fputs(name, fp);
gets(name);
}
printf("BYE!\n");
// 파일 닫기.
fclose(fp);
}
fprintf()
지정된 형식을 가지로 파일에 자료를 출력.
여러 항목의 복합적인 자료로 구성된 레코드를 저장할 때 유용.
형식 : fprintf(파일포인터변수, "출력형식", 변수);
사용 예 : fprintf(fp, "%s %d\n", a, b);
기능 : 지정된 형식대로 자료를 파일포인터 변수가 가리키는 곳에 출력.
#include <stdio.h>
#include <stdlib.h>
void main()
{
FILE *fp;
char no[10], name[10];
int mid, term, rep, att, i;
if ((fp = fopen("03_fprintf.tt.txt", "w")) == NULL)
{
puts("CAN NOT OPEN FILE");
exit(1);
}
// stdout : 모니터를 가리키는 특수한 파일포인터.
fprintf(stdout, "insert no name mid term rep att.");
for (i = 0; i < 5; ++i)
{
scanf("%s %s %d %d %d %d", no, name, &mid, &term, &rep, &att);
// 지정된 형식으로 자료를 파일에 출력.
fprintf(fp, "%10s %8s %3d %3d %3d %3d\n", no, name, mid, term, rep, att);
}
printf("BYE!\n");
// 파일 닫기.
fclose(fp);
}
C 언어에서 입출력 장치를 파일 개념으로 처리
자동적으로 3개의 표준 파일에 대한 포인터를 생성함.
이러한 표준 파일에 대해서는 다로 파일포인터를 선언할 필요가 없음.
표준파일
파일 포인터
대응 장치
입력
stdin
키보드
출력
stdout
모니터
에러
stderr
모니터
순차파일 입력함수
파일 출력함수에 의해 만들어진 순차파일의 저장된 자료를 읽어내는 함수. 자료를 읽을 때는 파일의 끝에 있는 EOF 신호를 만날 때까지 읽을 수 있는 프로그램 작성.
getc(), fgetc(), fgets(), fscanf()
getc()
문자 단위의 파일 입력함수.
fgetc() 함수와 유사.
형식 : getc(파일포인터변수);
사용예 : c = getc(fp);
기능 : 지정된 파일로부터 한 문자를 읽어온다.
#include <stdio.h>
#include <stdlib.h>
void main() {
FILE *fp;
char c;
if ((fp = fopen("01_putc.tt.txt", "r")) == NULL) {
puts("\n\nCAN NOT OPEN FILE");
exit(1);
}
while ((c = getc(fp)) != EOF) {
putchar(c);
}
printf("\n\nBYE!\n");
// 파일 닫기.
fclose(fp);
}
fgets()
파일에 저장된 문자열 자료를 읽을 때 사용.
읽어 낼 문자열의 길이를 반드시 명시.
형식 : fget(문자열변수, 문자열 길이 + 1, 파일포인터 편수);
사용 예 : fget(s, 40, fp);
기능 : 지정된 파일로부터 해당 문자열 길이 만큼의 문자를 읽어 문자열 변수에 저장한다.
#include <stdio.h>
#include <stdlib.h>
void main() {
char name[20];
FILE *fp;
if ((fp = fopen("02_fputs.tt.txt", "r")) == NULL) {
puts("\n\nCAN NOT OPEN FILE");
exit(1);
}
// 파일의 끝에 도달할 때까지 읽기.
while (fgets(name, 20, fp) != NULL) {
printf("%s", name);
}
printf("\n\nBYE!\n");
// 파일 닫기.
fclose(fp);
}
scanf()
숫자, 문자 등 복합적인 자료로 구성된 레코드를 읽을 때 사용.
일반적으로 파일의 끝을 판별하는 feof()와 같이 사용.
형식 : fscanf(파일포인터변수, "입력형식", 변수);
사용 예 : fscanf(sp, "%s %d", &a, &b);
기능 : 파일 포인터가 가리키는 곳으로부터 지정된 형식대로 자료를 읽어온다.
#include <stdio.h>
#include <stdlib.h>
void main() {
FILE *fp;
char no[10], name[10];
int mid, term, rep, att;
if ((fp = fopen("03_fprintf.tt.txt", "r")) == NULL) {
puts("\n\nCAN NOT OPEN FILE");
exit(1);
}
printf("no name mid, term, rep, att\n");
// 파일의 끝인지 확인하는 feof()
while (!feof(fp)) {
// 파일에 저장된 자료의 형식에 맞게 입력형식을 지정해야 함.
fscanf(fp, "%10s %8s %3d %3d %3d %3d\n", no, name, &mid, &term, &rep, &att);
printf("%-10s %-8s %4d %4d %4d %4d\n", no, name, mid, term, rep, att);
}
printf("\n\nBYE!\n");
// 파일 닫기.
fclose(fp);
}
레코드 추가를 위한 사용 모드
a a+ ab ab+
형식 : fp = fopen("파일명", "a");
사용 예 : fp = fopen("파일명", "a");
기능 : 이미 만들어진 순차파일의 끝에 새로운 레코드 추가(append).
#include <stdio.h>
void main() {
FILE *fp;
// 레코드 추가 모드로 파일 개방.
fp = fopen("04_tt.dat", "a");
// 파일이 없으르모 새 파일 생성 후 새 내용 기록.
fputs("asdf \n", fp);
fputs("qwer \n", fp);
fputs("zxcv \n", fp);
fputs("qaz \n", fp);
fputs("wsx \n", fp);
fclose(fp);
}
랜덤파일 처리 (random file)
파일의 임의의 위치에서 자료를 읽거나 쓸 수 있음.
레코드의 길이가 일정함.
순차파일에 비해
장점 : 레코드 탐색이 빠르고 효과적.
단점 : 기억공간 낭비.
랜덤파일 열기
일반적으로 랜덤파일을 입출력할 때는 2진 모드로 파일을 개방.
2진 모드의 특징
텍스트 파일보다 적은 기억공간.
레코드의 길이를 개발자가 결정.
파일 포인터의 위치 변경 가능.
랜덤파일 입출력 함수
fwrite()
레코드의 길이를 지정.
자료저장 변수는 포인터 형.
형식 : fwirte(저장자료변수, 레코드길이, 레코드개수, 파일포인터);
사용 예 : fwrite(name, 10, 1, fp);
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void main()
{
FILE *fp;
char name[10];
// 2진 파일 쓰기 모드 개방.
if ((fp = fopen("08_fwrite.dat", "wb")) == NULL)
{
puts("\n\nCAN NOT OPEN FILE");
exit(1);
}
gets(name);
while (strcmp(name, "END"))
{
// 2진 파일 쓰기.
fwrite(name, 10, 1, fp);
gets(name);
}
fclose(fp);
}
fread()
읽기에 성공하면 읽은 레코드 수를 리턴.
형식 : fread(읽을자료변수, 레코드길이, 레코드개수, 파일포인터);
ex : fread(name, 10, 2, fp);
#include <stdio.h>
#include <stdlib.h>
void main() {
FILE *fp;
char name[10];
// 2진 파일 읽기 모드 개방.
if ((fp = fopen("08_fwrite.dat", "rb")) == NULL) {
puts("\n\nCAN NOT OPEN FILE");
exit(1);
}
while (1) {
// 레코드의 개수가 1이 아닌 값이 리턴되면 파일은 끝난다.
if (fread(name, 10, 1, fp) != 1)
break;
puts(name);
}
fclose(fp);
}
프로그램과 입출력 장치(콘솔, 파일, 소켓등)와의 사잉에 이루어 지는 자료의 입력과 출력.
자료의 입출력을 위한 논리넉인 통로 : 스트림
스트림 (stream)
stream
표준 입출력장치를 이용한 자료 입출력.
표준 입출력장치와의 스트림은 프로그램 실행/종료 시 자동으로 생성/소멸 됨.
파일 입출력을 위한 스트림은 프로그램을 통해 생성/소멸 시켜주어야 함.
파일 입출력의 수행 과정
과정
파일을 연다.
파일과 자료를 주고 받을 수 있는 스트림을 생성(fopen() 사용).
입출력을 수행한다.
파일을 닫는다.
생성된 스트림을 소멸시키기 위한 과정(fclose() 사용).
스트림(stream)의 생성
파일과 프로그램과의 통로(논리적인 접속)를 구성.
통로 역할을 파일포인터가 수행.
파일입출력 프로그램 구조
// 파일을 가리키는 파일포인터 선언.
FILE *fp;
// 파일 열기 : 지정한 모드로 열고, fp로 하여금 파일을 가리키게 함.
fp = fopen("파일명", "모드");
// 입출력 수행 : 파일처리함수와 fp를 이용하여 입출력 수행.
...
// 파일 닫기 : 버퍼를 비우고 fp가 가리키는 파일을 닫음.
fclose(fp);