1TB Firebird 데이터베이스: 예비 보고서
드미트리 쿠즈멘코, 최종 업데이트 2014-03-31
더 큰 (1.7 테라바이트) 데이터베이스에 대한 기사 읽기: 1.7 테라바이트 데이터베이스에 대한 자세한 내용.
테라바이트 Firebird 데이터베이스를 만드는 이유는 무엇인가?
많은 회사들이 대용량 Firebird 데이터베이스로 작업하며 중요한 비즈니스 운영을 지원하기 위해 이를 신뢰합니다. 일부 Firebird 데이터베이스는 이미 수백 기가바이트 크기에 이르렀고 계속 성장하고 있으며( “누가 큰가?” 섹션 참조), 2배, 3배 또는 5배 더 커질 시점을 쉽게 예측할 수 있습니다. 따라서 데이터베이스 관리자와 공급업체는 대용량 데이터베이스에서 Firebird의 동작을 조사하고 이를 관리하는 방법에 대한 권장 사항을 얻는 데 관심이 있습니다.
또한 1Tb Firebird 데이터베이스를 만들면서 염두에 두었던 중요한 이유는 Firebird를 “소규모 데이터베이스"용 데이터베이스 엔진으로 보는 널리 퍼진 인식을 최종적으로 없애는 것이었습니다. 이 신화는 이제 사라진 것 같지만 일부 분석가와 언론인은 정기적으로 이 신화를 다시 꺼내며, 우리는 마침내 이 터무니없는 인식을 끝내기를 바랍니다.
| ## 하드웨어 |
Firebird는 놀라운 확장성으로 잘 알려져 있으며 이 조사는 이를 다시 한번 확인했습니다. 이 실험의 초기 목적은 단지 1Tb 크기의 Firebird 데이터베이스를 만드는 것이었으므로 일반적인 데스크톱 컴퓨터를 사용했습니다:
표 1: 하드웨어
| 구성 요소 | 매개변수 |
| CPU | AMDAthlon 64 x2 5200 |
| RAM | 4GB |
| 메인보드 | MSI K9N Platinum |
| HDD1 (운영 체제 및 임시) | ST3160815AS, 160GB, SATA II |
| HDD2 (보조) | HDT721064SLA360, 640GB, SATA II |
| HDD2 (보조) | HDS728080PLA380, 80GB, SATA I |
| HDD3 (데이터베이스) | ST31500341AS, 1.5TB, SATA II (펌웨어 CC1H) |
본질적으로 우리는 사무실 데스크톱 중 하나에 1.5Tb HDD를 다른 수정 없이 장착했습니다. 이 HDD는 클러스터 크기 16Kb로 포맷되었습니다(아래에서 볼 수 있듯이 데이터베이스의 페이지 크기와 동일).
소프트웨어
데스크톱 컴퓨터이므로 운영 체제는 Windows XP Professional SP3, 32비트입니다. 실제로 테스트를 수행하기 위해 TPC 기반 툴킷의 로더를 사용했습니다(http://ibdeveloper.com/tests/tpc-c/에서 다운로드, 바이너리와 소스 모두 제공).
로더는 실제 시나리오에서 삽입되는 방식으로 데이터를 삽입한다는 점을 강조하고 싶습니다: 레코드는 테이블별로가 아니라 여러 마스터-디테일-서브디테일 테이블에 삽입되어 데이터베이스 내부(및 물리적 디스크 영역)에 배치됩니다.
표 2: 소프트웨어
| 소프트웨어 | 버전 |
| 운영 체제 | Windows XP Professional SP3, 32비트 |
| Firebird | 2.1.3 SuperServer (스냅샷) |
| 로더 | tpc 기반 테스트의 사용자 정의 로더 |
계획
이 실험을 위한 매우 간단한 계획이 있었습니다:
- 데이터베이스를 만들고 인덱스 없이 1Tb 데이터를 로드
- 기본 키와 적절한 인덱스 생성 (실제로 데이터베이스 크기가 1Tb 이상)
- 데이터베이스 통계 수집
- 여러 SQL 쿼리 실행 및 데이터베이스 성능 평가
데이터베이스 및 Firebird 서버 구성
데이터베이스는 페이지 크기가 16384바이트로 HDD 클러스터와 동일하며, 디스크 처리량을 최대화하기 위해(한 I/O 주기에서 1페이지 읽기/쓰기) 설정되었습니다.
Firebird 구성에서는 임시 공간을 위한 추가 디렉토리를 구성하고 640Gb 디스크(약 300Gb 여유 공간)를 가리키도록 했습니다.
로드 단계
데이터는 여러 단계로 이 데이터베이스에 로드되었습니다. 로드 작업 중 컴퓨터는 일반적인 데스크톱으로 사용되었습니다(MS Office, Firefox, IBAnalyst 등 약 8-12개의 프로그램이 동시에 실행됨). 이 작업에만 하드웨어를 전용으로 사용했다면 더 빨랐을 것이므로 이러한 값은 저사양 예로만 간주하시기 바랍니다; 확실히 최고 결과는 아닙니다.
표 3: 로드 작업
| |
| 설명 | 값 |
| 로드 시간 | 약 70시간 |
| 삽입된 총 레코드 수 | 62억 |
| 평균 삽입 속도 | 초당 24500 레코드 |
| 평균 레코드 크기 | 146바이트 (최소 13바이트, 최대 - 600바이트) |
| 트랜잭션 | 646489 |
로드에 약 4일을 소비했고, 그 후 정확히 1Tb 크기(즉, 1 099 900 125 184바이트)의 Firebird 데이터베이스를 얻었습니다.
아래에서 FBDataGuard 뷰어에서 데이터베이스 성장 및 트랜잭션 동향을 볼 수 있습니다:

인덱스
인덱스를 하나씩 생성하고 생성 시간과 정렬에 사용된 임시 파일의 적절한 크기를 측정했습니다.
가장 큰 인덱스는 ORDER_LINE 테이블용으로 생성되었습니다. 기본 키는 4개의 필드(Smallint, Smallint, Integer 및 Smallint)를 포함합니다. 이 정렬 인덱스의 임시 파일은 182Gb였고, 데이터베이스의 최종 인덱스 크기는 29.3Gb입니다.
흥미로운 점은 38억 개의 레코드가 있는 테이블의 인덱스도 페이지 크기가 16384바이트이므로 깊이 = 3이라는 것입니다. 따라서 이 테이블의 기본 키를 사용한 데이터 검색에는 오버헤드가 없습니다.
통계
그 후 데이터베이스 통계를 수집했습니다. 7시간 32분 45초가 걸렸습니다.
주요 통계 정보를 하나의 테이블에 넣고 일부 쿼리와 시간 측정을 포함했습니다:
표 4: 1Tb 데이터베이스에 대한 통합 통계
| 테이블 이름 | 레코드 수 | 크기, gb | select count(*) 실행 시간 | 인덱스 생성 시간 | 임시 파일 크기, Gb | 인덱스 크기, Gb |
| WAREHOUSE | 1240 | 0.002 | 0s | 0 | 0 | 0.0 | | ITEM | 100000 | 0.012 | 0.7s | - | - | 0.0 | | DISTRICT | 124000 | 0.017 | 0.7s | 6 | - | 0.0 | | NEW_ORDER | 111600000 | 32 | 20m 00s | 23m 00s | 4.56 | 0.8 | | CUSTOMER | 372000000 | 224 | - | 41m 00s | - | 2.6 | | customer_last | | | | 1h 52m 32s | 12.4 | 2.3 | | fk_cust_ware | | | | 2h 10m 51s | - | 2.3 | | HISTORY | 372000000 | 32 | - | - | - | - | | ORDERS | 372000000 | 25 | 32m 00s | 45m 41s | 15.2 | 2.5 | | STOCK | 1240000000 | 404 | - | 3h 34m 44s | 41.5 | 9.2 | | ORDER_LINE | 3720051796 | 359 | - | 12h 6m 18s | 182.0 | 29.3 |
데이터베이스 통계는 여기에서 다운로드할 수 있습니다.
무료 FBDataGuard Community Edition Viewer를 사용하여 텍스트 데이터를 해석하고 데이터베이스 성능 지표뿐만 아니라 CPU 및 메모리 사용량도 확인할 수 있습니다.
쿼리
먼저 여러 테이블에 대해 select count(*) 쿼리를 실행했습니다(위 표 4의 4번째 열 참조). 아시다시피 Firebird의 다중 버전 특성상 전체 테이블에 대한 select count(*) 는 서버가 모든 페이지를 방문해야 하므로 비용이 많이 드는 작업입니다. 경험 많은 Firebird 개발자는 select count(*)를 사용하지 않지만, 우리는 데이터베이스와 하드웨어의 전반적인 성능 비율을 입증하기 위해 이를 사용했습니다.
select count 쿼리 후에는 실제 시나리오의 쿼리를 실행했으며, 솔직히 말해 그렇게 좋은 결과에 놀랐습니다. 직접 확인해 보세요:
| 쿼리 | 통계 | 설명 |
| select w_id, w_name, c_id, c_last from WAREHOUSE, customer where c_w_id = w_id |
PLAN JOIN (WAREHOUSE NATURAL, CUSTOMER INDEX (FK_CUST_WARE)) ------ 성능 정보 —— 준비 시간 = 15ms 실행 시간 = 79ms 평균 가져오기 시간 = 6.08 ms 현재 메모리 = 272 264 476 최대 메모리 = 272 514 048 메모리 버퍼 = 16 384 디스크에서 캐시로 읽기 = 82 캐시에서 디스크로 쓰기 = 0 캐시에서 가져오기 = 3 648 |
12400개 및 372000000개 레코드가 있는 테이블의 단순 조인, WHERE 조건 없음. “평균 가져오기 시간 = 6.08 ms"는 첫 번째 행을 가져오는 시간입니다. |
| select w_id, w_name, c_id, c_last from WAREHOUSE, customer where c_w_id = w_id and c_w_id = 10000 |
PLAN JOIN (WAREHOUSE INDEX (WAREHOUSE_PK), CUSTOMER INDEX (FK_CUST_WARE)) ------ 성능 정보 —— 준비 시간 = 16ms 실행 시간 = 78ms 평균 가져오기 시간 = 6.00 ms 현재 메모리 = 272 266 148 최대 메모리 = 272 514 048 메모리 버퍼 = 16 384 디스크에서 캐시로 읽기 = 88 캐시에서 디스크로 쓰기 = 0 캐시에서 가져오기 = 3 656 |
최근 레코드 선택을 강제하는 조건이 있는 동일한 테이블의 조인. “평균 가져오기 시간 = 6.00 ms"는 첫 번째 행을 가져오는 시간입니다. |
| select count(*) from WAREHOUSE, customer where c_w_id = w_id and c_w_id = 10000 결과 = 30000 |
PLAN JOIN (WAREHOUSE INDEX (WAREHOUSE_PK), CUSTOMER INDEX (FK_CUST_WARE)) ------ 성능 정보 —— 준비 시간 = 0ms 실행 시간 = 453ms 평균 가져오기 시간 = 453.00 ms 현재 메모리 = 272 263 844 최대 메모리 = 272 514 048 메모리 버퍼 = 16 384 디스크에서 캐시로 읽기 = 1 048 캐시에서 디스크로 쓰기 = 0 캐시에서 가져오기 = 60 024 |
이전 쿼리의 레코드 수 계산 |
| SELECT * FROM ORDER_LINE WHERE OL_W_ID = 500 |
Plan PLAN (ORDER_LINE INDEX (ORDER_LINE_PK)) ------ 성능 정보 —— 준비 시간 = 0ms 실행 시간 = 94ms 평균 가져오기 시간 = 7.23 ms 현재 메모리 = 136 445 536 최대 메모리 = 136 592 176 메모리 버퍼 = 8 192 디스크에서 캐시로 읽기 = 150 캐시에서 디스크로 쓰기 = 0 캐시에서 가져오기 = 2 402 |
가장 큰 테이블(3.8B 레코드)에 대한 쿼리. “평균 가져오기 시간 = 7.23 ms"는 첫 번째 행을 가져오는 시간입니다. |
<br>Plan<br><br>PLAN (ORDER_LINE INDEX (ORDER_LINE_PK))<br><br> <br><br>------ 성능 정보 ------<br><br>준비 시간 = 0ms<br><br>실행 시간 = 3s 438ms<br><br>평균 가져오기 시간 = 0.01 ms<br><br>현재 메모리 = 136 445 496<br><br>최대 메모리 = 136 592 176<br><br>메모리 버퍼 = 8 192<br><br>디스크에서 캐시로 읽기 = 1 840<br><br>캐시에서 디스크로 쓰기 = 0<br><br>캐시에서 가져오기 = 598 636<br> |
||
| SELECT * FROM ORDER_LINE WHERE OL_W_ID = 500 |
가장 큰 테이블(3.8B 레코드)에 대한 동일한 쿼리이지만, 이번에는 모든 레코드(299245개 레코드)를 가져왔습니다. | |
| select w_id, w_name, c_id, c_last from WAREHOUSE, customer where c_w_id = w_id and (c_w_id > 8000) and (c_w_id < 10000) |
Plan PLAN JOIN (WAREHOUSE INDEX (WAREHOUSE_PK), CUSTOMER INDEX (FK_CUST_WARE)) ------ 성능 정보 —— 준비 시간 = 0ms 실행 시간 = 125ms 평균 가져오기 시간 = 9.62 ms 현재 메모리 = 272 270 824 최대 메모리 = 272 514 048 메모리 버퍼 = 16 384 디스크에서 캐시로 읽기 = 91 캐시에서 디스크로 쓰기 = 0 캐시에서 가져오기 = 3 659 |
1240개 레코드와 372M개 레코드가 있는 테이블 조인. |
| select count(*) from WAREHOUSE, customer where c_w_id = w_id and (c_w_id > 8000) and (c_w_id < 10000) 결과 = 59 970 000 |
Plan PLAN JOIN (WAREHOUSE INDEX (WAREHOUSE_PK), CUSTOMER INDEX (FK_CUST_WARE)) ------ 성능 정보 —— 준비 시간 = 0ms 실행 시간 = 13m 4s 718ms 평균 가져오기 시간 = 784 718.00 ms 현재 메모리 = 272 268 532 최대 메모리 = 272 514 048 메모리 버퍼 = 16 384 디스크에서 캐시로 읽기 = 2 332 583 캐시에서 디스크로 쓰기 = 0 캐시에서 가져오기 = 119 977 902 |
이전 쿼리의 레코드 수 계산 |
요약
이 실험에서 Firebird는 다음과 같은 결과를 보여주었습니다.
-
대용량 데이터베이스를 처리할 수 있는 확실한 능력. 적절한 하드웨어에서 32Tb 데이터베이스를 생성하고 사용하는 것이 가능하며, Firebird는 더 작은 데이터베이스(즉, 1Tb 이하)에서 보여주는 것과 동일한 높은 성능을 보여줄 것이라고 확신합니다.
-
우수한 확장성과 놀라울 정도로 작은 설치 공간. 1Tb 데이터베이스는 일반 데스크톱 컴퓨터에서 생성되었으며, 더 중요한 것은 일반 쿼리를 수행하는 데 사용할 수 있다는 점입니다: 수백만 개의 레코드를 가져오지 않는다면 쿼리 속도는 중간 크기 데이터베이스(10-15Gb)와 동일합니다.
이것이 이 실험의 끝이 아닙니다: 우리는 몇 가지 쿼리를 실행하고 추가 통계를 수집하여 곧 더 자세한 보고서를 게시할 계획입니다. 계속 지켜봐 주시기 바랍니다.
연락처
모든 질문과 문의 사항은 [email protected]으로 보내주십시오.