2009-05-11 2 views
11

고유 한 문자열 필드와 몇 개의 정수 필드가있는 데이터베이스 테이블이 있습니다. 문자열 필드는 보통 10-100 자입니다.수천 개의 레코드를 테이블에 삽입하는 가장 효율적인 방법은 무엇입니까? (MySQL, Python, Django)

1 분에 한 번 다음과 같은 시나리오가 있습니다. 테이블의 레코드 구조에 해당하는 2-10,000 개의 튜플 목록을받습니다.

[("hello", 3, 4), ("cat", 5, 3), ...] 

이러한 튜플을 모두 테이블에 삽입해야합니다 (데이터베이스에 이러한 문자열이 나타나지 않는다고 가정). 설명을 위해 InnoDB를 사용하고 있는데이 테이블에 대한 자동 증분 기본 키를 가지고 있는데 문자열은 PK가 아닙니다.

내 코드는 현재이 목록을 통해 반복은 각 튜플에 해당하는 값으로 파이썬 모듈 객체를 생성하고, ".save()", 무언가과 같이 호출

@transaction.commit_on_success 
def save_data_elements(input_list): 
    for (s, i1, i2) in input_list: 
     entry = DataElement(string=s, number1=i1, number2=i2) 
     entry.save() 

이 코드는 현재 하나입니다 내 시스템의 성능 병목 현상에 대해 잘 알고 있으므로 최적화 할 방법을 찾고 있습니다.

예를 들어, 100 개의 튜플에 대한 INSERT 명령을 포함하는 SQL 코드를 생성하고 실행할 수는 있지만 성능이 향상되는지는 알 수 없습니다.

이러한 프로세스를 최적화하기위한 제안이 있으십니까?

감사합니다.

+0

좋은 질문입니다! 그래서 최고의 답은 텍스트 파일을 생성하거나 문자열 연결을 통해 SQL 쿼리를 생성하는 것 같습니다. 이것은 약간 만족스럽지 않습니다! – JAL

답변

11

당신은 .. 형식 "필드 1", "FIELD2"의 파일에 행을 작성하고 다음 그런 다음이 실행 그들에게

data = '\n'.join(','.join('"%s"' % field for field in row) for row in data) 
f= open('data.txt', 'w') 
f.write(data) 
f.close() 

를로드 LOAD 데이터를 사용할 수 있습니다

LOAD DATA INFILE 'data.txt' INTO TABLE db2.my_table; 

Reference

+0

코드가 데이터베이스 서버에서 실행되고 있지 않으면 LOAD DATA LOCAL INFILE 여야합니다. – staticsan

+0

또한로드하기 전에 인덱스를 비활성화 한 다음 나중에 활성화하십시오 (인덱스를 작성하는 데 시간이 오래 걸립니다). 장고 삽입에 도움이되는지 보지 못했습니다. – pufferfish

12

MySQL의 경우 특히 데이터를로드하는 가장 빠른 방법은 LOAD DATA INFILE이므로 예상되는 형식으로 데이터를 변환 할 수 있다면 아마도 테이블에 넣는 가장 빠른 방법 일 것입니다.

+0

유일한 잠재적 인 문제는 save() 메서드를 재정의하는 것입니다. 이렇게하면 디자인에 대해 두 번 생각해야합니다. –

+0

@ S.Lott : "save()"를 재정의한다는 것은 무엇을 의미합니까? "load data infile"에서 손실 될 코드를 통해 저장하는 동안 사전/사후 처리 작업이 수행되도록 모듈 클래스의 .save() 메서드를 재정의하는지 여부를 의미합니까? 그렇다면 그건 사실이 아닙니다. 나는. save()를 무시하지 않고 있습니다. 그렇지 않으면 정교하게하십시오 ... 감사합니다 –

4

다른 제안 중 일부는, 당신이 당신의 삽입이 속도를 위해 할 수있는 두 가지를 언급대로 LOAD DATA INFILE을하지 않으면 :

  1. 사용이 제표를 작성 - 모든
  2. 단일 트랜잭션에 삽입을 모두 수행 삽입이는 SQL 구문 분석의 오버 헤드를 잘라 -이 (이노 같은) 거래
  3. 을 지원하는 DB 엔진을 사용하여 필요
+0

@Sean : "prepared statements"에 감사드립니다. 문자열/숫자 목록을 제공하여 많은 "% s"요소를 가진 SQL 코드를 의미합니까? 또한, 내 코드를 보아주세요. (질문의 본문에서) - 올바르게 이해한다면 @ transaction.commit_on_success 데코레이터를 사용하여 이미 하나의 트랜잭션을 사용하고 있습니다. (InnoDB를 사용하고 있습니다) –

+0

저는 정말로 아닙니다. 장고와 함께하는 일에 대해 궁금해 할 것입니다. MySQL을 사용하는 일반적인 배경에서 왔기 때문에 거래와 관련하여 어떤 일이 일어나는지 알지 못합니다. Prepared statements에 대해서는 DataElement 객체의 구현 세부 사항 인 것 같습니다. 준비된 문장은 다음과 같습니다 :'stmt = Prepare (sqlStatement); 'db.execute (sqlStatement, var1, var2 ...) '보다는 stmt.execute (var1, var2 ..)'- 매번 구문 분석하기보다는 정규 표현식을 컴파일하는 것과 같습니다. –

4

손으로 굴릴 수 있다면 INSERT 성명서를 입력하면됩니다. 복수 값 절을 사용하는 단일 INSERT 문은 많은 개별 INSERT 문보다 훨씬 빠릅니다.

+1

@staticsan : 그러한 진술에 "실용적인"제한이 있다고 생각합니까? 즉, 데이터베이스에 10k 줄의 텍스트가 포함 된 단일 INSERT 쿼리를 보낼 수 있습니까? –

+0

유일한 실제 제한은 네트워크 버퍼의 크기입니다. 이 기본값은 수년 동안 1Mb 였지만 많은 사람들이 최대 16MB로 늘 렸습니다. 최신 버전의 MySQL은 큰 패킷 크기조차도 지원할 수 있습니다. – staticsan

+1

패킷 크기는 레코드 수보다 많습니다. 삽입 버퍼를 빌드 할 때 버퍼를 최대 mysql 패킷 크기 이상으로두면 더 이상 추가하지 마십시오. 나는 벤치마킹을하고 이득이 어디에서 평준화되기 시작하는지 볼 것입니다. mysql> @@ max_allowed_packet \ G : @@ max_allowed_packet : 33554432 – Will

1

이것은 DB 로의 실제 데이터로드와 관련이 없지만 ...

"데이터로드 중 ...로드가 곧 완료됩니다."사용자에게 메시지 유형이 옵션 인 경우 다른 스레드에서 INSERT 또는 LOAD DATA를 비동기 적으로 실행할 수 있습니다.

다른 점이 있습니다.

+0

더 많은 문제는 서버가이 입력을 처리하는 데 너무 바빠서 다른 요청을 처리 할 수 ​​없다는 것입니다. . –

+0

나는 별도의 스레드에서 이미 처리를하고있다. (사용자가이 작업이 끝나기를 기다리지 않고있다.) 내 문제는 시스템이 너무 바빠서 대기열이 충분히 정리 될 확률이 충분하지 않다는 것이다. 시간 ... –

2

삽입 방법에 관계없이 최대 읽기/쓰기 동시성을 위해 InnoDB 엔진을 사용하고자 할 것입니다. MyISAM은 삽입하는 동안 전체 테이블을 잠글 것이지만, InnoDB (대부분의 경우)는 영향을받은 행만 잠그기 때문에 SELECT 문이 진행될 수있다.

+0

고마워, 내가 InnoDB를 사용하고 있다는 설명을 추가했다. –

1

정확한 세부 정보는 모르겠지만 json 스타일의 데이터 표현을 사용하고 비품 등으로 사용할 수 있습니다. Douglas Napoleone의 Django Video Workshop에서 비슷한 것을 보았습니다. 동영상보기 : http://www.linux-magazine.com/online/news/django_video_workshophttp://www.linux-magazine.com/online/features/django_reloaded_workshop_part_1. 희망이 도움이됩니다.

희망을 찾으실 수 있습니다. 방금 장고를 배우기 시작 했으므로 자원으로 안내 할 수 있습니다.