2010-05-21 37 views
5

Tôi đang phân tích nhật ký và chèn nó vào MySQL hoặc SQLite bằng SQLAlchemy và Python. Ngay bây giờ tôi mở một kết nối đến DB, và khi tôi lặp qua mỗi dòng, tôi chèn nó sau khi nó được phân tích cú pháp (Đây chỉ là một bảng lớn ngay bây giờ, không phải là rất có kinh nghiệm với SQL). Sau đó tôi đóng kết nối khi vòng lặp được thực hiện. Mã tóm tắt là:Chèn nhanh hơn các bản ghi vào một bảng với SQLAlchemy

log_table = schema.Table('log_table', metadata, 
         schema.Column('id', types.Integer, primary_key=True), 
         schema.Column('time', types.DateTime), 
         schema.Column('ip', types.String(length=15)) 
.... 
engine = create_engine(...) 
metadata.bind = engine 
connection = engine.connect() 
.... 
for line in file_to_parse: 
    m = line_regex.match(line) 
    if m: 
     fields = m.groupdict() 
     pythonified = pythoninfy_log(fields) #Turn them into ints, datatimes, etc 
     if use_sql: 
      ins = log_table.insert(values=pythonified) 
      connection.execute(ins) 
      parsed += 1 

hai câu hỏi của tôi là:

  • Có cách nào để tăng tốc độ chèn trong khuôn khổ cơ bản này? Có thể có một Queue chèn và một số chủ đề chèn, một số loại chèn số lượng lớn, vv?
  • Khi tôi sử dụng MySQL, khoảng 1,2 triệu bản ghi thời gian chèn là 15 phút. Với SQLite, thời gian chèn là hơn một giờ. Liệu sự khác biệt thời gian giữa các công cụ db có vẻ đúng hay không có nghĩa là tôi đang làm điều gì đó rất sai?
+0

Tôi cũng nên nói rằng khi tôi tự hỏi về cách tăng tốc, ý tôi là có điều gì đó cơ bản mà tôi nên làm và không phải điều đó sẽ mang lại cho tôi lợi ích lớn (tức là ít nhất hơn 25% tăng tốc độ thời gian).Tốc độ không phải là bản chất ở đây, tôi chỉ tự hỏi nếu tôi đang làm một cái gì đó trong một cách đi bộ vì đây là tất cả mới với tôi. –

Trả lời

4

Điều quan trọng bạn nên thử là đặt giao dịch xung quanh nhiều lần chèn vì đó là cam kết của cơ sở dữ liệu vào đĩa thực sự mất nhiều thời gian. Bạn sẽ cần phải quyết định mức phối liệu, nhưng một nỗ lực thô đầu tiên sẽ là quấn một giao dịch quanh toàn bộ lô.

+0

Vì vậy, một cái gì đó giống như một mảng của các đối tượng ins tôi tạo ra, và sau đó thực hiện khi mảng đầy? Hay đó không thực sự là ý của bạn? –

+0

@Kyle: Bạn cần phải tạo một giao dịch với transaction = session.create_transaction(); và sau đó làm transaction.commit. Xem http://www.rmunn.com/sqlalchemy-tutorial/tutorial.html và cuộn xuống tiêu đề "Giao dịch". –

+0

Không thực sự những gì tôi đã làm, nhưng đây là ý tưởng đằng sau những gì tôi đã làm và muốn cung cấp cho mọi người điểm :-). Giải thích những gì tôi đã làm dưới đây. –

3

Nếu không biết động cơ bảng (MyISAM? InnoDB?), Lược đồ và chỉ mục, thật khó để nhận xét về chi tiết cụ thể giữa hai cơ sở dữ liệu bạn đang sử dụng ở đó.

Tuy nhiên, khi sử dụng MySQL như thế này, bạn có thể thấy rằng việc ghi dữ liệu của mình nhanh hơn vào tệp văn bản tạm thời và sau đó là use the LOAD DATA INFILE syntax để tải tất cả vào cơ sở dữ liệu của bạn. Có vẻ như you can call the execute method on your connection object để chạy SQL cần thiết để thực hiện việc này. Ngoài ra, nếu bạn đã chết khi thêm mọi thứ theo hàng và bạn đang tạo lại bảng mỗi lần, bạn có thể xác minh các ràng buộc chính trong chương trình của mình và thêm các ràng buộc đó chỉ sau khi tất cả các hàng đã được chèn vào, lưu DB thời gian thực hiện các ràng buộc kiểm tra trên mỗi lần chèn.

+0

"bạn có thể xác minh các ràng buộc chính trong chương trình của bạn và thêm những ràng buộc đó chỉ sau khi tất cả các hàng đã được chèn vào, lưu DB thời gian thực hiện kiểm tra trên mỗi lần chèn." Bạn có thể phá vỡ nó xuống một chút cho tôi, phần đó đã đi qua đầu của tôi: -P –

+0

@Kyle Thật khó để cung cấp cho cụ thể mà không có một lược đồ bảng để làm việc từ. Nhưng, ví dụ, nếu bạn có bất kỳ chỉ số UNIQUE nào, tính duy nhất đó là một ràng buộc trên bảng. Mỗi khi bạn chèn một hàng, cơ sở dữ liệu đảm bảo rằng không có hàng nào khác xung đột với hàng đó. Vì bạn chỉ có một bảng, bạn không phải lo lắng về các ràng buộc khoá ngoại, nhưng nếu bạn nên thêm những điều sau này, điều này cũng sẽ áp dụng cho chúng. –

2

tôi đã làm như sau để đạt được một số trạm trộn:

inserts = [] 
insert_every = 1000 
for line in file_to_parse: 
    m = line_regex.match(line) 
    if m: 
     fields = m.groupdict() 
     if use_sql: #This uses Globals, Ick :-/ 
      inserts.append(pythonified) 
      if (parsed % insert_every) == 0: 
       connection.execute(log_table.insert(), inserts) 
       inserts = [] 
      parsed += 1 
if use_sql: 
    if len(inserts) > 0: 
     connection.execute(log_table.insert(), inserts) 

này không sử dụng các giao dịch, nhưng theo một cách rất lười biếng nó cho phép tôi để biến chèn/phân tích giai đoạn từ ~ 13 giây xuống còn khoảng ~ 2 giây với chương trình phụ trợ mysql sử dụng mẫu nhỏ hơn. Tôi sẽ thấy những gì sự khác biệt giữa mysql và sqlite bây giờ với sự thay đổi này bằng cách sử dụng mẫu đầy đủ.

Tôi đã tìm thấy thông tin cơ bản cho số here này.

Kết quả:
Động cơ: Non-nhóm Insert Time in Minutes: nhóm Insert Time in Minutes
Sqlite: 61: 8
MySql: 15: 2,5

Tôi không tuôn bộ nhớ cache của tôi giữa mysql và sqlite mà có thể đã có tệp văn bản nguồn có thể, nhưng tôi không nghĩ rằng đó sẽ là một sự khác biệt tương đối đáng kể.

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