1,000M 행 MySQL 테이블 작성


18

이 질문은 의견 제안, 복제에 대한 사과를 기반으로 스택 오버플로 에서 다시 게시됩니다 .

질문

질문 1 : 데이터베이스 테이블의 크기가 커짐에 따라 LOAD DATA INFILE 호출 속도를 높이기 위해 MySQL을 어떻게 조정할 수 있습니까?

질문 2 : 컴퓨터 클러스터를 사용하여 다른 CSV 파일을로드하거나 성능을 향상 시키거나 종료합니까? (이것은로드 데이터 및 대량 삽입을 사용하는 내일의 벤치마킹 작업입니다)

이미지 검색을 위해 다양한 기능 검출기와 클러스터링 파라미터 조합을 시도하고 있으며, 그 결과 대규모 데이터베이스를 적시에 구축 할 수 있어야합니다.

기계 정보

머신은 256 기가의 램을 가지고 있으며 데이터베이스를 배포하여 생성 시간을 향상시키는 방법이 있다면 같은 양의 램으로 사용할 수있는 또 다른 2 개의 머신이 있습니까?

테이블 스키마

테이블 스키마는 다음과 같습니다

+---------------+------------------+------+-----+---------+----------------+
| Field         | Type             | Null | Key | Default | Extra          |
+---------------+------------------+------+-----+---------+----------------+
| match_index   | int(10) unsigned | NO   | PRI | NULL    |                |
| cluster_index | int(10) unsigned | NO   | PRI | NULL    |                |
| id            | int(11)          | NO   | PRI | NULL    | auto_increment |
| tfidf         | float            | NO   |     | 0       |                |
+---------------+------------------+------+-----+---------+----------------+

로 만든

CREATE TABLE test 
(
  match_index INT UNSIGNED NOT NULL,
  cluster_index INT UNSIGNED NOT NULL, 
  id INT NOT NULL AUTO_INCREMENT,
  tfidf FLOAT NOT NULL DEFAULT 0,
  UNIQUE KEY (id),
  PRIMARY KEY(cluster_index,match_index,id)
)engine=innodb;

지금까지 벤치마킹

첫 번째 단계는 이진 파일에서 빈 테이블로의 대량 삽입과로드를 비교하는 것이 었습니다.

It took:  0:09:12.394571  to do  4,000  inserts with 5,000 rows per insert
It took: 0:03:11.368320 seconds to load 20,000,000 rows from a csv file

성능의 차이를 감안할 때 바이너리 CSV 파일에서 데이터를로드 할 때 먼저 아래 호출을 사용하여 100K, 1M, 20M, 200M 행을 포함하는 바이너리 파일을로드했습니다.

LOAD DATA INFILE '/mnt/tests/data.csv' INTO TABLE test;

2 시간 후에 200M 행 이진 파일 (~ 3GB csv 파일)로드를 종료했습니다.

그래서 스크립트를 실행하여 테이블을 만들고 이진 파일에서 다른 수의 행을 삽입 한 다음 테이블을 삭제하십시오 (아래 그래프 참조).

여기에 이미지 설명을 입력하십시오

이진 파일에서 1M 행을 삽입하는 데 약 7 초가 걸렸습니다. 그런 다음 특정 데이터베이스 크기에서 병목 현상이 발생하는지 확인하기 위해 한 번에 1M 행 삽입 벤치마킹하기로 결정했습니다. 데이터베이스가 약 59M 행에 도달하면 평균 삽입 시간이 약 5,000 / 초로 떨어졌습니다.

여기에 이미지 설명을 입력하십시오

global key_buffer_size = 4294967296을 설정하면 작은 이진 파일을 삽입 할 때 속도가 약간 향상되었습니다. 아래 그래프는 다른 행 수에 대한 속도를 보여줍니다.

여기에 이미지 설명을 입력하십시오

그러나 1M 행을 삽입해도 성능이 향상되지 않았습니다.

행 : 1,000,000 시간 : 0 : 04 : 13.761428 인서트 / 초 : 3,940

빈 데이터베이스 대

행 : 1,000,000 시간 : 0 : 00 : 6.339295 인서트 / 초 : 315,492

최신 정보

다음 순서를 사용하여로드 데이터 수행

SET autocommit=0;
SET foreign_key_checks=0;
SET unique_checks=0;
LOAD DATA INFILE '/mnt/imagesearch/tests/eggs.csv' INTO TABLE test_ClusterMatches;
SET foreign_key_checks=1;
SET unique_checks=1;
COMMIT;
여기에 이미지 설명을 입력하십시오

따라서 이것은 생성되는 데이터베이스 크기 측면에서 상당히 유망 해 보이지만 다른 설정은로드 데이터 파일 호출의 성능에 영향을 미치지 않는 것으로 보입니다.

그런 다음 다른 컴퓨터에서 여러 파일을로드하려고 시도했지만 load data infile 명령은 파일의 크기가 커서 다른 컴퓨터의 시간이 초과되어 테이블을 잠급니다.

ERROR 1205 (HY000) at line 1: Lock wait timeout exceeded; try restarting transaction

이진 파일에서 행 수 늘리기

rows:  10,000,000  seconds rows:  0:01:36.545094  inserts/sec:  103578.541236
rows:  20,000,000  seconds rows:  0:03:14.230782  inserts/sec:  102970.29026
rows:  30,000,000  seconds rows:  0:05:07.792266  inserts/sec:  97468.3359978
rows:  40,000,000  seconds rows:  0:06:53.465898  inserts/sec:  96743.1659866
rows:  50,000,000  seconds rows:  0:08:48.721011  inserts/sec:  94567.8324859
rows:  60,000,000  seconds rows:  0:10:32.888930  inserts/sec:  94803.3646283

솔루션 : 자동 증분을 사용하는 대신 MySQL 외부에서 ID 사전 계산

와 테이블을 구축

CREATE TABLE test (
  match_index INT UNSIGNED NOT NULL,
  cluster_index INT UNSIGNED NOT NULL, 
  id INT NOT NULL ,
  tfidf FLOAT NOT NULL DEFAULT 0,
  PRIMARY KEY(cluster_index,match_index,id)
)engine=innodb;

SQL로

LOAD DATA INFILE '/mnt/tests/data.csv' INTO TABLE test FIELDS TERMINATED BY ',' LINES TERMINATED BY '\n';"

여기에 이미지 설명을 입력하십시오

스크립트가 인덱스를 사전 계산하도록하는 것은 데이터베이스의 크기가 커짐에 따라 성능 저하를 제거한 것으로 보입니다.

업데이트 2-메모리 테이블 사용

인 메모리 테이블을 디스크 기반 테이블로 이동하는 비용을 고려하지 않고 약 3 배 더 빠릅니다.

rows:  0  seconds rows:  0:00:26.661321  inserts/sec:  375075.18851
rows:  10000000  time:  0:00:32.765095  inserts/sec:  305202.83857
rows:  20000000  time:  0:00:38.937946  inserts/sec:  256818.888187
rows:  30000000  time:  0:00:35.170084  inserts/sec:  284332.559456
rows:  40000000  time:  0:00:33.371274  inserts/sec:  299658.922222
rows:  50000000  time:  0:00:39.396904  inserts/sec:  253827.051994
rows:  60000000  time:  0:00:37.719409  inserts/sec:  265115.500617
rows:  70000000  time:  0:00:32.993904  inserts/sec:  303086.291334
rows:  80000000  time:  0:00:33.818471  inserts/sec:  295696.396209
rows:  90000000  time:  0:00:33.534934  inserts/sec:  298196.501594

데이터를 메모리 기반 테이블에로드 한 다음 청크 로 디스크 기반 테이블 복사하여 10 분 59.71 초의 오버 헤드가 발생하여 쿼리와 함께 107,356,741 행을 복사합니다.

insert into test Select * from test2;

100M 개의 행을로드하는 데 약 15 분이 소요되며 이는 디스크 기반 테이블에 직접 삽입하는 것과 거의 같습니다.


1
기본 키를 변경하는 id것이 더 빠를 것이라고 생각합니다 . (나는 당신이 이것을 찾고 있지 않다고 생각하지만)
DavidEG

안녕하세요 데이비드는 의견 주셔서 감사합니다, 불행히도 키없이 쿼리 우리는 충분히 빠르지 못해 (기본 키 선택 뒤에 논리는이 게시물에 설명되어 있습니다 할 필요가 stackoverflow.com/questions/4282526/mysql-group-by- 최적화 )
Ben

1
이것은 단지 테스트를위한 것입니까? MySQL MEMORY 엔진을 살펴보고 싶을 것입니다 : dev.mysql.com/doc/refman/5.0/en/memory-storage-engine.html 이것을 아키텍처로 배포 할 계획이라면 어떻게 할 것인지 궁금합니다. 실패로부터 복구하면 MapReduce / Hadoop이 더 잘 처리하는 것처럼 보입니다.
다항식

팁에 감사드립니다. 데이터베이스가 일단 생성되면 (현재 사양에서는) 크게 변하지 않을 것입니다
Ben

답변:


4

좋은 질문-잘 설명했습니다.

LOAD DATA INFILE 호출 속도를 높이기 위해 MySQL을 어떻게 튜닝 할 수 있습니까?

키 버퍼에 대해 이미 높은 설정을 가지고 있지만 충분합니까? 나는 이것이 64 비트 설치라고 가정하고 (그렇지 않으면 가장 먼저해야 할 일은 업그레이드) MSNT에서 실행되지 않는다고 가정합니다. 몇 가지 테스트를 실행 한 후 mysqltuner.pl의 출력을 살펴보십시오.

캐시를 가장 효과적으로 사용하려면 입력 데이터를 일괄 처리 / 사전 정렬 할 때 이점이있을 수 있습니다 ( 'sort'명령의 최신 버전에는 큰 데이터 세트를 정렬하는 데 많은 기능이 있습니다). 또한 MySQL 외부에서 ID 번호를 생성하면 더 효율적일 수 있습니다.

컴퓨터 클러스터를 사용하여 다른 CSV 파일을로드하는 경우

출력 집합을 단일 테이블로 사용한다고 가정하면 더 많은 데이터베이스가 필요하지 않은 ID 정렬 및 생성 작업을 분산시키는 것이 유일한 이점입니다. 데이터베이스 클러스터를 사용하는 OTOH는 경합 관련 문제 (성능 문제 이외의 다른 것으로 보지 않아야 함)를 얻게됩니다.

데이터를 샤딩하고 결과 데이터 세트를 독립적으로 처리 할 수 ​​있다면 성능상의 이점을 얻을 수 있습니다. 그러나 이것이 각 노드를 튜닝 할 필요성을 부정하지는 않습니다.

sort_buffer_size에 대해 최소 4GB가 있는지 확인하십시오.

그 외에도 성능의 제한 요소는 디스크 I / O에 관한 것입니다. 이 문제를 해결하는 방법에는 여러 가지가 있지만 최적의 성능을 위해 SSD에서 미러링 된 스트라이프 데이터 세트를 고려해야합니다.


1
  • 제한 요인을 고려하십시오. 거의 단일 스레드 CPU 처리입니다.
  • 이미 load data...삽입보다 빠르다고 판단 했으므로 사용하십시오.
  • 이미 큰 파일 (행 번호 기준)이 속도를 늦추는 것으로 이미 결정했습니다. 그것들을 조각으로 나누고 싶습니다.
  • 겹치지 않는 기본 키를 사용하여 백만 행을 사용하여 최소한 N * CPU 세트를 대기열에 넣습니다 (아마도).
  • 각 파일에서 기본 키의 순차적 블록을 사용하십시오.

정말 멋지고 싶다면 단일 파일을 명명 된 파이프 모음에 공급하고 삽입 인스턴스를 관리하는 다중 스레드 프로그램을 만들 수 있습니다.

요약하면, 워크로드를 MySQL로 튜닝 할 때 MySQL을 튜닝하지 않습니다.


-1

나는 syntacx를 정확하게 기억하지 못하지만 그것이 inno db라면 외래 키 검사를 끌 수 있습니다.

또한 가져온 후에 인덱스를 만들 수 있으며 실제로 성능을 향상시킬 수 있습니다.


인덱스 재 구축을 지연하면 테이블에 이미있는 행 수가 추가하는 행 수보다 훨씬 적은 성능 만 향상됩니다.
symcbean
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.