2009-09-09 5 views
2

루프에 500-5000 개의 새 데이터베이스 INSERT를 만드는 장고보기가 있습니다. 문제는, 정말 느립니다! 나는 Postgres 8.3에서 분당 약 100 개의 인서트를 얻고있다. 우리는 더 작은 하드웨어 (더 작은 EC2 인스턴스)에서 MySQL을 사용 했었지만 이러한 유형의 속도 문제는 결코 없었습니다.ORM에서 데이터베이스 삽입 속도 향상

세부 사항 : Postgres 8.3 on Ubuntu Server 9.04. 서버는 EBS (ext3)의 데이터베이스가있는 "대형"Amazon EC2 - 11GB/20GB입니다. 정상에서

for k in kw: 
     k = k.lower() 
     p = ProfileKeyword(profile=self) 
     logging.debug(k) 
     p.keyword, created = Keyword.objects.get_or_create(keyword=k, defaults={'keyword':k,}) 
     if not created and ProfileKeyword.objects.filter(profile=self, keyword=p.keyword).count(): 
      #checking created is just a small optimization to save some database hits on new keywords 
      pass #duplicate entry 
     else: 
      p.save() 

일부 출력 : -

여기

내 postgresql.conf의 일부입니다 나를 더

shared_buffers = 4000MB 
effective_cache_size = 7128MB 

내 파이썬이 필요하면 알려

top - 16:56:22 up 21 days, 20:55, 4 users, load average: 0.99, 1.01, 0.94 
Tasks: 68 total, 1 running, 67 sleeping, 0 stopped, 0 zombie 
Cpu(s): 5.8%us, 0.2%sy, 0.0%ni, 90.5%id, 0.7%wa, 0.0%hi, 0.0%si, 2.8%st 
Mem: 15736360k total, 12527788k used, 3208572k free, 332188k buffers 
Swap:  0k total,  0k used,  0k free, 11322048k cached 

    PID USER  PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND                                    
14767 postgres 25 0 4164m 117m 114m S 22 0.8 2:52.00 postgres                                    
    1 root  20 0 4024 700 592 S 0 0.0 0:01.09 init                                     
    2 root  RT 0  0 0 0 S 0 0.0 0:11.76 migration/0                                   
    3 root  34 19  0 0 0 S 0 0.0 0:00.00 ksoftirqd/0                                   
    4 root  RT 0  0 0 0 S 0 0.0 0:00.00 watchdog/0                                   
    5 root  10 -5  0 0 0 S 0 0.0 0:00.08 events/0                                    
    6 root  11 -5  0 0 0 S 0 0.0 0:00.00 khelper                                    
    7 root  10 -5  0 0 0 S 0 0.0 0:00.00 kthread                                    
    9 root  10 -5  0 0 0 S 0 0.0 0:00.00 xenwatch                                    
    10 root  10 -5  0 0 0 S 0 0.0 0:00.00 xenbus                                    
    18 root  RT -5  0 0 0 S 0 0.0 0:11.84 migration/1                                   
    19 root  34 19  0 0 0 S 0 0.0 0:00.01 ksoftirqd/1 

다른 세부 정보가 도움이되는지 알려주십시오.

답변

3

첫째, ORM 연산은 항상 순수 SQL보다 느리게 진행됩니다. ORM 코드에서 대용량 데이터베이스에 대한 업데이트를 작성한 후 실행을 설정했지만 몇 시간 만 지나면 그 작업이 종료되었습니다. SQL로 다시 작성한 후 모든 작업이 1 분 이내에 완료되었습니다.

둘째, 여기에 코드가 데이터 세트에있는 모든 행에 대해 네 가지 별도의 데이터베이스 작업까지하고있다 염두에 곰 - get get_or_create의 가능성도 create, 필터에 count, 그리고 마지막으로 save합니다. 그것은 많은 데이터베이스 액세스입니다.

최대 5000 개의 개체가 크지 않다는 것을 염두에두고 처음부터 전체 데이터 집합을 메모리로 읽을 수 있어야합니다. 그런 다음 하나의 filter을 사용하여 기존의 모든 키워드 개체를 한 번에 가져와 키워드 get_or_create에 많은 수의 쿼리를 저장하고 처음부터 중복 된 ProfileKeywords를 인스턴스화하지 않아도됩니다.

+0

+1 모든 것을 한꺼번에 읽는 것이 더 효율적이며, 여분의 필터를 매번 사용하지 않는 것이 좋습니다. –

+0

@Daniel Roseman : "기존의 모든 Keywords 개체를 얻기 위해 단일 필터를 수행 할 수 있습니다 ..."에 대해 약간 확장 할 수 있습니까? 실제로 데이터베이스에 이미 수백만 개의 Keywords 객체가 있으므로 메모리에 모두 읽어 들이고 싶지는 않습니다. 한 번에 5000 개의 새 객체를 삽입하려고합니다. – erikcw

+0

Keyword.objects.filter (keyword__contains = ...)를 사용하여 관련 키워드 객체를 메모리에 읽었습니다. 스크립트는 이제 10 초 이내에 실행됩니다 !! 또한 트랜잭션 세이브 포인트를 추가했습니다 .... – erikcw

6

이렇게 느린 대량 작업을 수행하는 일반적인 이유 중 하나는 자체 트랜잭션에서 각 삽입이 발생한다는 것입니다. 모든 트랜잭션을 단일 트랜잭션으로 처리 할 수 ​​있다면 훨씬 빠르게 처리 할 수 ​​있습니다.

+1

+1 내 추측도 마찬가지입니다. @erikcw : http://docs.djangoproject.com/en/dev/topics/db/transactions/ –

+0

에 따라 거래를 관리하십시오. 거의 확실한 답변입니다. 단일 삽입 트랜잭션은 트랜잭션 내에서 다중 삽입을 수행하는 것보다 반드시 느립니다. – wlashell