이 질문은 의견 제안, 복제에 대한 사과를 기반으로 스택 오버플로 에서 다시 게시됩니다 .
질문
질문 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 분이 소요되며 이는 디스크 기반 테이블에 직접 삽입하는 것과 거의 같습니다.
id
것이 더 빠를 것이라고 생각합니다 . (나는 당신이 이것을 찾고 있지 않다고 생각하지만)