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