1.1.1 • Published 6 months ago

frankdb v1.1.1

Weekly downloads
-
License
MIT
Repository
github
Last release
6 months ago

NPM version

FRANK 를 소개합니다!

FRANK 는 RANK() 함수를 매우 빠르게 제공하는 데이터베이스입니다. 스택 오버플로우 등을 서베이하면 기존의 RDBMS 에서 RANK() 함수가 느린데, 어떻게 최적화 하냐는 글을 볼 수 있습니다. 사실 RANK() 함수는 전체 레코드를 정렬하여 하나씩 세아려야 하는 매우 무거운 함수로, 이 쿼리를 최적화 하는 데에는 한계가 있습니다. FRANK는 다른 데이터베이스와 함께 사용하여 RANK 의 성능을 극대화하고자 할 때 사용할 수 있습니다.

기존 RDBMS 에서 RANK() 함수의 시간복잡도는 O(nlogn) 입니다. FRANK 는 기존 rdbms 에서 사용하는 B+Tree 이외에도 Dynamic Segment Tree 를 사용하여 RANK() 함수를 O(log(range(n))) 에 제공합니다. 이는 10만개의 record 기준으로 RDBMS 에서는 100 번의 RANK() 함수를 호출하는데 약 15000ms 가 걸리지만, FRANK 는 단 10ms 에 모든 쿼리를 처리할 수 있습니다. record 가 늘어날수록 격차는 더 커집니다.

언제 사용할 수 있나요?

  1. 레코드의 수가 매우 클 때 사용할 수 있습니다.

레코드 수가 충분히 크지 않은 경우에는 RDBMS 에 내장된 RANK() 함수를 사용하여도 속도 문제가 없습니다. 다만 어느 수준을 넘어서게 되면 RANK() 함수가 급격하게 느려지게 됩니다. RANK() 쿼리 부하가 시스템의 운영에 부담을 줄 수 있다고 판단되면 FRANK 를 사용할 수 있습니다.

  1. 스케줄링을 통한 준 실시간 RANK 제공이 매력적이지 않을 때 사용할 수 있습니다.

FRANK 를 사용하지 않는 경우에도 실시간을 포기하고 RANK() 결과를 제공하는 방법이 있습니다. 스케줄링을 통해 주기적으로 전체 레코드의 RANK 를 구해 새로운 테이블에 저장해놓고, 해당 결과를 제공하는 방법입니다. 다만 이 경우에 RANK 는 부정확한 값을 반환하며, 스케줄링을 관리하는 것과 관련된 여러 엔지니어링 부담이 발생할 수 있습니다.

어떻게 사용하나요?

아래와 같이 설치해주세요

npm install frankdb

FRANK 는 key-value store 구조를 가지고 있습니다. 아래와 같이 key 와 value 의 타입을 지정하여 초기화할 수 있습니다.

  • key 는 any, string, number 중 하나를 지정할 수 있으며, default 는 any 입니다.
  • value 는 number 의 tuple 로 구성되며, point 의 하한과 상한을 지정해주어야 합니다. 범위가 작을수록 효율적으로 동작할 수 있으나 그 크기는 미미하기 때문에 넉넉하게 잡아주셔도 좋습니다.
  • nodejs 의 실수 오차 문제로 인해 -2^53 ~ 2^53 의 범위에서만 선언할 수 있습니다.
import FRANK from "frankdb";

const DB = FRANK({
    keyType: 'any',
    valueType: [
        {min: 0, max: 65535, order: 'asc'}, 
        {min: 0, max: 1e9, order: 'desc'},
    ]
});

FRANK 는 다음과 같은 쿼리를 제공합니다.

...
const session = DB.session();

await session.insert('cat', [65, 12345]);
await session.insert('dog', [65, 23456]);

await session.rank('cat'); // 1
await session.rank('dog'); // 0

await session.update('cat', [65, 34567]);
await session.remove('dog');

await session.exists('cat'); // true
await session.exists('dog'); // false

어떠한 기능이 개발될 예정인가요?

현재 FRANK 는 nodejs 패키지로 작성되어 nodejs 에서만 npm 을 통해 모듈을 설치하여 사용할 수 있습니다.

만약 이 데이터베이스가 유용하고 redis 및 다른 데이터베이스와 같은 범언어 오픈소스로 작성될 필요가 있다고 생각하신다면 ⭐️ 을 눌러주세요!

벤치마크 테스트 내용

아래와 같이 벤치마크 테스트를 진행하였습니다.

환경

  • SEED : 1234
  • Database : MySQL
  • CPU : Apple M1
  • Network : localhost

테스트 실행

아리와 같이 .env 파일에 환경변수를 입력한다.

DB_HOST=localhost
DB_USER=
DB_NAME=

RANDOM_SEED=1234
QUERY_COUNT=
RECORD_COUNT=

테스트를 실행한다.

npm run benchmark

유저 테이블은 다음과 같이 선언한다.

CREATE TABLE User (
    id    VARCHAR(16)  NOT NULL PRIMARY KEY,
    grade VARCHAR(1)   NOT NULL,
    point INT          NOT NULL,
    date  DATETIME     NOT NULL,
    INDEX idx_user_ranking (grade, point DESC, date DESC)
);

RANK 쿼리는 다음과 같이 실행한다.

SELECT ranking
FROM (
    SELECT
        id,
        RANK() OVER (ORDER BY grade ASC, point DESC, date DESC) as ranking
    FROM User
) AS RankedSubQuery
WHERE id = ?;

설명

  • A 는 MySQL 을 독립적으로 사용하는 경우, B 는 MySQL 과 FRANK 를 함께 사용하는 경우이다.
  • update, rank 쿼리의 수는 100개로 유지하며, record 의 수를 각각 10,000, 100,000, 1,000,000 으로 실험한다.
  • updqte 쿼리는 insert, delete, update 를 랜덤으로 실행한다.
  • B 에서 insert, update 는 MySQL 과 FRANK 에 모두 반영하며, rank 는 FRANK 를 통해서만 결과를 얻는다.

결과

  • 업데이트 쿼리의 경우 B가 A에 비해 1~3배 가량의 시간이 더 소요되었으나, RANK 를 호출하는 경우 시간을 획기적으로 단축한다.
  • 레코드의 수가 늘어날수록 rank 쿼리 최적화율이 높아진다.
10,000AB
insert148 ms213 ms
rank1341 ms7 ms
update62 ms61 ms
100,000AB
insert976 ms1924 ms
rank15833 ms10 ms
update58 ms56 ms
1,000,000AB
insert12592 ms37818 ms
rank385089 ms24 ms
update180 ms339 ms
1.1.1

6 months ago

1.1.0

6 months ago

1.0.5

6 months ago

1.0.4

6 months ago

1.0.3

6 months ago

1.0.2

6 months ago

1.0.1

6 months ago

1.0.0

6 months ago