2009-07-16 32 views
61

Tôi phải chèn hơn 8000 bản ghi vào cơ sở dữ liệu SQLite bằng cách sử dụng ORM của Django. Hoạt động này cần phải được chạy như một cronjob khoảng một lần mỗi phút.
Hiện tại tôi đang sử dụng vòng lặp for để lặp qua tất cả các mục và sau đó chèn từng mục một.
Ví dụ:Cách hiệu quả để chèn hàng nghìn bản ghi vào bảng SQLite bằng Django là gì?

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

một cách hiệu quả để làm điều này là gì?

Chỉnh sửa: So sánh một chút giữa hai phương pháp chèn.

Without commit_manually trang trí (11.245 hồ sơ):

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

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

Sử dụng trang trí commit_manually (11.245 hồ sơ):

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

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

Lưu ý: Các kiểm tra kịch bản cũng thực hiện một số hoạt động khác ngoài chèn vào cơ sở dữ liệu (tải xuống tệp ZIP, trích xuất tệp XML từ lưu trữ ZIP, phân tích cú pháp tệp XML) để thời gian cần thiết để thực thi không cần thiết rily đại diện cho thời gian cần thiết để chèn các bản ghi.

Trả lời

104

Bạn muốn xem django.db.transaction.commit_manually.

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

Vì vậy, nó sẽ là một cái gì đó như:

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() 

Mà sẽ chỉ cam kết một lần, thay vì tại mỗi save().

Trong django 1.3 trình quản lý ngữ cảnh đã được giới thiệu. Vì vậy, bây giờ bạn có thể sử dụng transaction.commit_on_success() theo cách tương tự:

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() 

Trong django 1.4, bulk_create đã được bổ sung, cho phép bạn tạo danh sách các đối tượng mô hình của bạn và sau đó cam kết tất cả chúng cùng một lúc.

LƯU Ý phương thức lưu sẽ không được gọi khi sử dụng tạo hàng loạt.

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

Trong django 1.6, transaction.atomic đã được giới thiệu, nhằm thay thế tại các chức năng di sản commit_on_successcommit_manually.

từ django documentation on atomic:

nguyên tử là có thể sử dụng cả hai như là một trang trí:

from django.db import transaction 

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

và như một người quản lý bối cảnh:

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

Thao tác này sẽ khởi tạo tất cả dưới dạng mô hình và chạy hàng nghìn lần chèn riêng lẻ. Tôi đã luôn luôn phải thả xuống SQL và thực hiện chèn hàng loạt thủ công cho loại ổ đĩa này; Django không được xây dựng cho nó. Nhưng có, bạn chắc chắn muốn một giao dịch duy nhất nếu bạn đang làm theo cách này. –

+0

Tôi không biết ORM Django tốt, nhưng không phải ORM chỉ tạo SQL cho bạn? Và trong một mô hình đơn giản không có khóa ngoài, không một cá thể đơn nào dịch sang một câu lệnh chèn đơn? – monkut

+0

Xin chào, bạn có thể vui lòng xây dựng cùng một điều khoản về .net? Nó sẽ là một trợ giúp lớn, vì tôi đang đối mặt với cùng một tình huống –

3

Hãy xem this. Nó có nghĩa là để sử dụng out-of-the-box với MySQL chỉ, nhưng có những gợi ý về những gì để làm cho cơ sở dữ liệu khác.

3

Bạn có thể nên tải xuống hàng loạt các mặt hàng - chuẩn bị tệp và sử dụng công cụ tải hàng loạt. Điều này sẽ hiệu quả hơn 8000 lần chèn riêng lẻ.

0

tôi khuyên bạn nên sử dụng SQL đơn giản (không ORM) bạn có thể chèn nhiều hàng bằng một lần chèn:

insert into A select from B; 

chọn từ B phần của sql của bạn có thể phức tạp như bạn muốn nó miễn là kết quả phù hợp với các cột trong bảng A và không có xung đột ràng buộc.

-3

Tôi đã gặp sự cố tương tự và tôi không thể tìm ra cách để thực hiện điều đó mà không có quá nhiều lần chèn. Tôi đồng ý rằng việc sử dụng các giao dịch có lẽ là cách đúng để giải quyết nó, nhưng đây là hack của tôi:

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

Điều này thực sự không khác với thực hiện lệnh save() trong vòng lặp for. Về cơ bản, bây giờ bạn lặp lại lần thứ hai để thực hiện tất cả các cuộc gọi save(). Nhưng Django vẫn sẽ làm cùng một lượng truy vấn chèn. Tối ưu hóa duy nhất là @monkut mô tả bằng cách sử dụng 'transaction.commit_manually'. –

2

Bạn nên kiểm tra DSE. Tôi đã viết DSE để giải quyết các loại vấn đề này (chèn hoặc cập nhật lớn). Sử dụng orm django là một kết thúc chết, bạn phải làm điều đó trong SQL đơn giản và DSE sẽ quan tâm nhiều đến điều đó cho bạn.

Thomas

+1

Một điều khác; Nếu bạn quyết định sử dụng SQL đơn giản và nếu SQL bạn đang chèn có cùng các trường mỗi lần, hãy thử sử dụng cursor.executemany (SQL, [danh sách các mục cần chèn]). Nhanh hơn nhiều so với chạy một chèn cho mỗi mục. – Weholt

2

Để trả lời câu hỏi đặc biệt là đối với SQLite với, như hỏi, trong khi tôi có chỉ là bây giờ khẳng định rằng bulk_create không cung cấp một Tăng tốc cực lớn có một giới hạn với SQLite: "Mặc định là tạo tất cả các đối tượng trong một lô, ngoại trừ SQLite, nơi mà mặc định là tối đa 999 biến cho mỗi truy vấn được sử dụng."

Nội dung được trích dẫn là từ tài liệu --- A-IV cung cấp liên kết.

Những gì tôi phải thêm là this djangosnippets mục nhập của alpar cũng có vẻ đang hoạt động đối với tôi. Đó là một trình bao bọc nhỏ phá vỡ lô lớn mà bạn muốn xử lý thành các lô nhỏ hơn, quản lý giới hạn biến 999.

Các vấn đề liên quan