Index
컴퓨터가 속도가 빠르다고 하지만 처리해야 될 데이터량이 많아지면 속도가 느려질 수밖에 없는데요. 이때 사용할 수 있는 방법이 index 입니다. index 는 일종에 특정 컬럼 값을 중심으로 미리 정렬을 해놓는 것입니다. 레코드가 정렬되어 있다고 가정하면 특정 연산을 빠르게 처리할 수 있고 메모리 사용량도 줄일 수가 있습니다.
- ORDER BY amount LIMIT 100 연산을 할 경우
레코드가 amount 값을 중심으로 정렬 되어있다고 가정하면 전체 데이터를 검색할 필요 없이 그냥 순차적으로 앞에서 100 개의 레코드를 출력하고 바로 연산을 종료할 수 있습니다.
- 레코드 값이 중복되어 저장될 경우 uniq 한 레코드만 출력하고자 할 때
만약에 전체 데이터 크기가 1G 이고 uniq 한 레코드가 700M, 중복되는 레코드가 300M 라고 한다면 awk 에서 group by 를 이용해 array 로 700M 를 메모리로 읽어들여야 하는데요. 간단히 테스트해보면 알 수 있지만 awk 에서는 메모리가 딱 700M 만 사용되지 않습니다. 실제 데이터의 약 15 배 이상 사용되는 것을 볼 수 있는데요 만약에 레코드가 정렬되어 있다고 가정하면 다음과 같이 처리가 가능하기 때문에 메모리가 거의 사용되지 않습니다.
$ awk -F, '
{ current = $0 }
previous != current { print }
{ previous = current }
' mydata > mydata.uniq
awk 는 database 가 아니기 때문에 따로 index 를 생성해서 사용하는 기능은 없습니다. 하지만 sort 명령을 이용해 미리 데이터를 정렬해놓은 다음 awk 명령을 사용하면 index 를 사용하는 효과를 볼 수 있습니다.
sort 명령도 실행 시에 메모리를 많이 사용합니다. 경우에 따라서 실제 데이터 크기의 10 배 이상 사용하는 것을 볼 수 있는데요 따라서 먼저 데이터를 작은 사이즈로 split 한 다음 개별 파일을 sort 하고 마지막으로 merge sort 를 해서 하나로 만들어야 합니다.
$ cat sort.sh
#!/bin/sh -e
dataFile=mydata_file # sort 하고자 하는 데이터 파일명
sortOptions="-t ',' -k3,3 -k2,2r" # FS 는 ',' 3번째 컬럼을 ASC 정렬하고 2번째 컬럼을 DESC 정렬
splitSize=100M # 100M 크기로 split
tmpFile=$(mktemp -p .)
split --additional-suffix=.split -C $splitSize "$dataFile"
for splitFile in *.split; do # sort 명령은 기본적으로
sort $sortOptions $splitFile > $tmpFile # multicore 를 사용합니다.
mv -f $tmpFile $splitFile
done
sort -m $sortOptions *.split > "$dataFile.sorted" # merge sort
rm -f *.split $tmpFile