답변:
https://dev.mysql.com/doc/refman/8.0/en/insert-optimization.html
행을 삽입하는 데 필요한 시간은 다음 요소에 의해 결정되며 숫자는 대략적인 비율을 나타냅니다.
- 연결 : (3)
- 서버로 쿼리 보내기 : (2)
- 구문 분석 쿼리 : (2)
- 행 삽입 : (1 × 행 크기)
- 인덱스 삽입 : (1 × 인덱스 수)
- 결산 : (1)
이것으로부터 하나의 큰 명령문을 보내면 삽입 명령문 당 7의 오버 헤드가 절약되며 텍스트를 더 읽으면 다음과 같이 표시됩니다.
동일한 클라이언트에서 동시에 많은 행을 삽입하는 경우 여러 값 목록과 함께 INSERT 문을 사용하여 한 번에 여러 행을 삽입하십시오. 이것은 별도의 단일 행 INSERT 문을 사용하는 것보다 훨씬 빠릅니다 (일부 경우에 여러 번 더 빠름).
나는이 질문을 받았다 거의 2 년 반 후에이 질문에 대답 해요 알고 있지만 난 그냥 지금 실제로 삽입 당 여러 VALUE 블록을하고 쇼 것을 내가 일하고 있어요 프로젝트에서 일부 하드 데이터를 제공하고 싶었다 훨씬 순차적 인 단일 VALUE 블록 INSERT 문보다 빠릅니다.
C # 에서이 벤치 마크를 위해 작성한 코드는 ODBC를 사용하여 MSSQL 데이터 소스 (~ 19,000 행, 모든 쓰기 시작 전에 읽음) 및 MySql .NET 커넥터 (Mysql.Data. *)에서 메모리로 데이터를 읽습니다. 준비된 명령문을 통해 메모리의 데이터를 MySQL 서버의 테이블에 삽입하십시오. 준비된 INSERT 당 VALUE 블록 수를 동적으로 조정할 수있는 방식으로 작성되었습니다 (즉, 한 번에 n 개의 행을 삽입하여 실행하기 전에 n 값을 조정할 수 있음). 각 n에 대해 여러 번.
단일 VALUE 블록 (예 : 한 번에 한 행)을 실행하는 데 5.7-5.9 초가 걸렸습니다. 다른 값은 다음과 같습니다.
한 번에 2 행 : 3.5-3.5 초
한 번에 5 행 : 2.2-2.2 초
한 번에 10 행
: 1.7-1.7 초 한 번에 50 행 : 1.17-1.18 초
한 번에 100 행 : 1.1-1.4 초
한 번에 500 행
: 1.1-1.2 초 한 번에 1000 행 : 1.17-1.17 초
따라서 2 ~ 3 개의 쓰기를 함께 묶어도 n = 5와 n = 10 사이의 어딘가에 도달 할 때까지 속도가 크게 향상됩니다 (런타임이 n 배만큼 줄어 듭니다). n = 10에서 n = 50 범위의 어딘가에서 개선은 무시할만한 수준이됩니다.
사람들이 (a) 다중 준비 아이디어를 사용할지 여부와 (b) 명령문 당 작성할 VALUE 블록 수 (최대 쿼리 크기를 초과하여 쿼리를 푸시하기에 충분히 큰 데이터로 작업하려는 경우)를 결정하는 데 도움이되는 희망 MySQL의 경우 서버의 max_allowed_packet 값에 따라 크거나 작은 많은 장소에서 기본적으로 16MB라고 생각합니다.)
트랜잭션 엔진을 사용하는지 여부와 자동 커밋을 설정했는지 여부가 주요 요인입니다.
자동 커밋은 기본적으로 켜져 있으며 그대로두고 싶을 것입니다. 따라서 수행하는 각 삽입은 자체 트랜잭션을 수행합니다. 즉, 행당 하나의 삽입을 수행하면 각 행마다 트랜잭션을 커밋하게됩니다.
단일 스레드를 가정하면 서버는 모든 행에 대해 일부 데이터를 디스크에 동기화해야합니다. 데이터가 지속적 저장 위치 (RAID 컨트롤러의 배터리 지원 램)에 도달 할 때까지 기다려야합니다. 이것은 본질적으로 다소 느리며 아마도 이러한 경우 제한 요소가 될 것입니다.
물론 트랜잭션 엔진 (보통 innodb)을 사용하고 내구성을 줄이기 위해 설정을 조정하지 않았다고 가정합니다.
또한 단일 인서트를 사용하여 이러한 인서트를 수행한다고 가정합니다. 여러 버전의 MySQL을 사용하면 일부 MySQL 버전에서 innodb에서 그룹 커밋이 작동하기 때문에 약간의 혼란을 겪습니다. 즉, 자체 커밋을 수행하는 여러 스레드가 트랜잭션 로그에 대한 단일 쓰기를 공유 할 수 있습니다. 이는 영구 저장소에 대한 동기화가 적기 때문에 좋습니다. .
반면에, 결과는 다열 인서트를 사용하고 싶다는 것입니다.
비생산적인 방법에는 한계가 있지만 대부분의 경우 10,000 행 이상입니다. 따라서 최대 1,000 개의 행을 배치하면 안전 할 것입니다.
MyISAM을 사용하고 있다면, 다른 많은 것들이 있지만, 나는 당신을 지루하지 않을 것입니다. 평화.
삽입과 관련하여 Mysql과 MariaDB가 얼마나 나쁜지에 대해서는 우스운 일입니다. 필자는 mysql 5.7과 mariadb 10.3을 테스트했지만 그 차이는 없습니다.
NVME 디스크, 70,000 IOPS, 1.1 GB / sec seq 처리량을 가진 서버에서 이것을 테스트했으며 전이중 (읽기 및 쓰기)이 가능합니다.
서버는 고성능 서버이기도합니다.
20GB의 램을 제공했습니다.
데이터베이스가 완전히 비어 있습니다.
내가받는 속도는 다중 행 삽입을 할 때 초당 5000 개의 삽입이었습니다 (1MB에서 최대 10MB 청크의 데이터로 시도)
단서 :
다른 스레드를 추가하고 SAME 테이블에 삽입하면 갑자기 2x5000 / sec가 발생합니다. 하나 이상의 스레드와 총 15000의 초당 속도가 있습니다.
한 번의 스레드 삽입을 수행하면 디스크에 순차적으로 쓸 수 있음을 의미합니다 (인덱스 제외). 스레드를 사용할 때 이제 훨씬 더 많은 임의 액세스를 수행해야하므로 실제로 가능한 성능이 저하됩니다. 그러나 현실 검사는 mysql이 너무 최적화되어 스레드가 많은 도움이된다는 것을 보여줍니다.
이러한 서버에서 가능한 실제 성능은 아마도 초당 수백만 개이고 CPU는 유휴 상태이며 디스크는 유휴 상태입니다.
그 이유는 mysql이 내부 지연을 갖는 것처럼 mariadb이기 때문입니다.
id
, parent_id
) VALUES (1, NULL) 있습니다. 다음 값 세트 중 하나가 해당 행에 연결됩니다. 덩어리로 분할하고 해당 세트를 다른 덩어리로 가져 오면 첫 번째 덩어리보다 먼저 처리되어 전체 프로세스가 실패 할 수 있습니다. 그 문제를 어떻게 해결할 수 있습니까?
여러 인서트가 더 빠르지 만 나사산이 있습니다. 또 다른 thrik은 임시 검사 삽입을 훨씬 더 빠르게 제한합니다. 테이블의 유무는 중요하지 않습니다. 예를 들어 외래 키 비활성화를 테스트하고 속도를 즐기십시오.
SET FOREIGN_KEY_CHECKS=0;
다음과 같은 방법으로 삽입 후 다시 켜야합니다.
SET FOREIGN_KEY_CHECKS=1;
이는 대량의 데이터를 삽입하는 일반적인 방법입니다. 데이터 무결성이 손상 될 수 있으므로 외래 키 검사를 비활성화하기 전에 데이터 무결성을 관리해야합니다.