[mysql] 여러 개의 단일 INSERT 또는 하나의 여러 행 INSERT가 더 빠릅니다.

MySQL에 데이터를 삽입하는 코드의 한 부분을 최적화하려고합니다. 하나의 거대한 다중 행 INSERT를 만들기 위해 INSERT를 연결해야합니까? 아니면 여러 개의 개별 INSERT가 더 빠릅니까?



답변

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을 사용하고 있다면, 다른 많은 것들이 있지만, 나는 당신을 지루하지 않을 것입니다. 평화.


답변

와이어를 통해 가능한 한 많은 인서트를 보내십시오. 실제 인서트 속도는 동일해야하지만 네트워크 오버 헤드가 줄어들면 성능이 향상됩니다.


답변

일반적으로 데이터베이스 호출 횟수가 적을수록 (빠르고 효율적 임) 더 좋으므로 데이터베이스 액세스를 최소화하는 방식으로 삽입물을 코딩하십시오. 연결 풀을 사용하지 않는 한 각 데이터베이스 액세스는 연결을 작성하고 SQL을 실행 한 다음 연결을 해제해야합니다. 상당히 약간의 오버 헤드!


답변

당신은 할 수 있습니다 :

  • 자동 커밋이 해제되어 있는지 확인
  • 열린 연결
  • 한 번의 트랜잭션으로 여러 배치의 인서트를 보냅니다 (약 4000-10000 행의 크기입니까?)
  • 연결을 닫습니다

서버 저울 (그 결정적으로 확인을 얼마나 잘에 따라 PostgreSQl, Oracle그리고 MSSQL), 다중 스레드와 다중 연결로 위의 일을.


답변

일반적으로 연결 오버 헤드로 인해 여러 인서트가 느려집니다. 한 번에 여러 개의 인서트를 사용하면 인서트 당 오버 헤드 비용이 줄어 듭니다.

사용중인 언어에 따라 db로 이동하기 전에 프로그래밍 / 스크립팅 언어로 배치를 작성하고 각 삽입을 배치에 추가 할 수 있습니다. 그런 다음 하나의 연결 작업을 사용하여 큰 배치를 실행할 수 있습니다. 다음 은 Java의 예입니다.