2009-07-16 18 views
61

Django'nun ORM'sini kullanarak bir SQLite veritabanına 8000+ kayıt eklemeliyim. Bu işlemin dakikada yaklaşık bir kez bir cronjob olarak çalıştırılması gerekiyor.
Şu anda tüm öğeler arasında yineleme yapmak için bir for döngüsü kullanıyorum ve ardından bunları tek tek takın.
Örnek:Django kullanarak binlerce kayıt bir SQLite tablosuna yerleştirmenin etkili bir yolu nedir?

for item in items: 
    entry = Entry(a1=item.a1, a2=item.a2) 
    entry.save() 

Bunu yapmanın etkili yolu nedir?

Düzeltme: İki ekleme yöntemi arasında küçük bir karşılaştırma. commit_manually dekoratör olmadan

(11245 kayıt):

[email protected] marinetraffic]$ time python manage.py insrec    

real 1m50.288s 
user 0m6.710s 
sys  0m23.445s 

commit_manually dekoratör Kullanma (11245 kayıt):

[[email protected] marinetraffic]$ time python manage.py insrec     

real 0m18.464s 
user 0m5.433s 
sys  0m10.163s 

Not: testi komut da diğer bazı işlemleri yapar takmadan yanında veritabanına (bir ZIP dosyasını indirir, ZIP arşivinden bir XML dosyası çıkarır, XML dosyasını ayrıştırır) böylece yürütme için gereken süre necessa olmaz Kayıtları eklemek için gereken zamanı temsil eder.

cevap

104

django.db.transaction.commit_manually ürününü incelemek istiyorsunuz. yerine her kaydetmek() at, sadece bir kez taahhüt edecektir

from django.db import transaction 

@transaction.commit_manually 
def viewfunc(request): 
    ... 
    for item in items: 
     entry = Entry(a1=item.a1, a2=item.a2) 
     entry.save() 
    transaction.commit() 

:

http://docs.djangoproject.com/en/dev/topics/db/transactions/#django-db-transaction-commit-manually

Yani şöyle bir şey olurdu. D1bgo 1.3'te, içerik yöneticileri tanıtıldı. Şimdi de benzer bir şekilde transaction.commit_on_success() kullanabilirsiniz: django 1.4 olarak

from django.db import transaction 

def viewfunc(request): 
    ... 
    with transaction.commit_on_success(): 
     for item in items: 
      entry = Entry(a1=item.a1, a2=item.a2) 
      entry.save() 

, bulk_create eklendi, size modeli nesnelerin listeleri oluşturabilir ve daha sonra hepsini birden işlemek için izin. Toplu oluşturma kullanırken kaydetme yöntemi çağrılmayacaktır. NOT.

django 1.6 içinde
>>> Entry.objects.bulk_create([ 
...  Entry(headline="Django 1.0 Released"), 
...  Entry(headline="Django 1.1 Announced"), 
...  Entry(headline="Breaking: Django is awesome") 
... ]) 

, transaction.atomic, kişiye eski işlevler artık commit_on_success ve commit_manually yerine amaçlanmıştır.django documentation on atomic den

: kullanılabilir

atomik

hem dekoratör olarak:
from django.db import transaction 

@transaction.atomic 
def viewfunc(request): 
    # This code executes inside a transaction. 
    do_stuff() 

ve bir bağlam yöneticisi olarak

: I düz SQL kullanarak tavsiye

from django.db import transaction 

def viewfunc(request): 
    # This code executes in autocommit mode (Django's default). 
    do_stuff() 

    with transaction.atomic(): 
     # This code executes inside a transaction. 
     do_more_stuff() 
+7

Bu, bunların tümünü model olarak başlatacak ve binlerce ayrı eklentiyi çalıştıracaktır. Her zaman SQL'e düşmek zorunda kaldım ve bu tür bir hacim için manuel toplu insertler yapmam gerekiyordu; Django bunun için inşa edilmedi. Ama evet, bu şekilde yapıyorsan kesinlikle tek bir işlem istiyorsun. –

+0

Bu Django ORM'yi iyi bilmiyorum ama ORM sizin için sadece SQL'i üretmiyor mu? Ve yabancı anahtar içermeyen basit bir modelde, tek bir deyim tek bir ekleme deyimine dönüşmez mi? – monkut

+0

Merhaba, lütfen aynı şeyi .net açısından detaylandırır mısınız? Aynı durumla karşılaştığım için çok iyi bir yardımcı olurdu. –

3

this'a bakın. Yalnızca MySQL ile kullanıma hazır hale getirildi, ancak diğer veritabanlarında ne yapılması gerektiğine dair işaretçiler var.

3

Öğeleri toplu olarak yüklemekten daha iyi olabilirsiniz - bir dosya hazırlayın ve toplu yükleme aracını kullanın. Bu, 8000 bireysel insertten çok daha verimli olacaktır.

0

(değil orm) Tek bir ek ile birden fazla satır ekleyebilirsiniz:

insert into A select from B; 

sql'ınızın B bölümünden arası seçim, sonuçların A tablosundaki sütunlarla eşleşmesi ve kısıtlama çakışmaları olmaması koşuluyla istediğiniz kadar karmaşık olabilir.

-3

Aynı soruna rastladım ve çok fazla ekleme olmadan bunu yapmanın bir yolunu çözemiyorum. Ben işlemlerini kullanarak çözmek için sağ yolu muhtemelen olduğunu kabul, ama burada benim kesmek:

def viewfunc(request): 
    ... 
    to_save = []; 
    for item in items: 
     entry = Entry(a1=item.a1, a2=item.a2) 
     to_save.append(entry); 
    map(lambda x: x.save(), to_save); 
+3

Bu aslında for döngüsünde save() çağrısını yapmaktan farklı değildir. Temel olarak, şimdi tüm save() çağrılarını yapmak için ikinci kez dönersiniz. Ancak Django, yine de aynı miktarda ekleme sorgusu yapacak. Tek optimizasyon, @monkut 'transaction.commit_manually' kullanılarak açıklanmaktadır. –

2

Sen DSE kontrol etmeliyiz. DSE'yi bu tür problemleri çözmek için yazdım (büyük ekler veya güncellemeler). Django orm kullanmak bir çıkmaz, bunu basit bir SQL'de yapmanız gerekiyor ve DSE sizin için çok şey hallediyor.

Thomas

+1

Başka bir şey; Düz SQL kullanmaya karar verirseniz ve eklediğiniz SQL her seferinde aynı alana sahipse, cursor.executemany (SQL, [eklenecek girişlerin listesi]) kullanmayı deneyin. Giriş başına bir insert çalıştırılmasından çok daha hızlı. – Weholt

2

özellikle SQLite ile ilgili soruya cevap vermek için, sadece şimdi bir sağlamak olmadığını bulk_create doğruladı muazzam hızlandırma SQLite ile bir sınırlama var: "Varsayılan, bir sorguda en fazla 999 değişken kullanıldığında olduğu gibi SQLite hariç, tüm nesneleri bir grupta oluşturmaktır."

Alıntı yapılan dokümanlar şu şekildedir: --- A-IV bir bağlantı sağlamıştır.

Eklemek zorunda olduğum şey, alpar tarafından yapılan this djangosnippets girişinin benim için çalışıyor gibi görünmesidir. Bu, 999 değişken limitini yöneterek, daha küçük gruplar halinde işlemek istediğiniz büyük partiyi kıran küçük bir ambalaj.

İlgili konular