2010-09-11 29 views
5

This post đề cập đến việc page này để hợp nhất cơ sở dữ liệu SQLite.Hợp nhất các tệp SQLite vào một tệp db và câu hỏi 'bắt đầu/cam kết'

Trình tự như sau. Giả sử tôi muốn hợp nhất a.db và b.db. Trong dòng lệnh tôi làm như sau.

  • sqlite3 a.db
  • đính kèm 'b.db' như Tom;
  • bắt đầu; < -
  • chèn vào điểm chuẩn * từ toM.benchmark;
  • cam kết; < -
  • tách cơ sở dữ liệu thành M;

Nó hoạt động tốt, nhưng trong trang được giới thiệu, người hỏi hỏi về tăng tốc và câu trả lời là sử dụng lệnh 'bắt đầu' và 'cam kết'.

Sau đó, tôi đã đưa ra mã python sau để làm điều tương tự. Tôi tóm tắt các lời gọi hàm SQLite với SQLiteDB và một trong số đó là phương thức runCommand(). Tôi đã nhận được lỗi tương tự mặc dù tôi xóa self.connector.commit().

# run command 
def runCommand(self, command): 
    self.cursor.execute(command) 
    self.connector.commit() # same error even though I delete this line 

db = SQLiteDB('a.db') 
cmd = "attach \"%s\" as toMerge" % "b.db" 
print cmd 
db.runCommand(cmd) 
cmd = "begin" 
db.runCommand(cmd) 
cmd = "insert into benchmark select * from toMerge.benchmark" 
db.runCommand(cmd) 
cmd = "commit" 
db.runCommand(cmd) 
cmd = "detach database toMerge" 
db.runCommand(cmd) 

Nhưng, tôi nhận được lỗi sau.

OperationalError: cannot commit - no transaction is active 

Mặc dù lỗi, kết quả db cũng được hợp nhất. Và không có sự bắt đầu/cam kết, không có lỗi gì cả.

  • Tại sao tôi không thể chạy lệnh bắt đầu/cam kết?
  • Hoàn toàn cần thiết để chạy bắt đầu/cam kết hợp nhất một cách an toàn các tệp db? Bài viết nói rằng mục đích bắt đầu/cam kết là để tăng tốc. Sau đó, sự khác biệt giữa việc sử dụng và không sử dụng lệnh bắt đầu/cam kết về mặt tăng tốc là gì?

Trả lời

11

Rõ ràng, Cursor.execute không hỗ trợ lệnh 'cam kết'. Nó hỗ trợ các lệnh 'bắt đầu' nhưng điều này là không cần thiết vì sqlite3 bắt đầu chúng cho bạn Anway:

>>> import sqlite3 
>>> conn = sqlite3.connect(':memory:') 
>>> cur = conn.cursor() 
>>> cur.execute('begin') 
<sqlite3.Cursor object at 0x0104B020> 
>>> cur.execute('CREATE TABLE test (id INTEGER)') 
<sqlite3.Cursor object at 0x0104B020> 
>>> cur.execute('INSERT INTO test VALUES (1)') 
<sqlite3.Cursor object at 0x0104B020> 
>>> cur.execute('commit') 

Traceback (most recent call last): 
    File "<pyshell#10>", line 1, in <module> 
    cur.execute('commit') 
OperationalError: cannot commit - no transaction is active 
>>> 

chỉ cần sử dụng các phương pháp trên đối tượng commitConnection của bạn.

Đối với câu hỏi thứ hai, bạn không cần phải bắt đầu/cam kết khi hợp nhất các tệp: chỉ cần chắc chắn rằng không có lỗi đĩa, sửa đổi db hoặc mọi người đang xem máy tính theo cách sai nó đang xảy ra. Vì vậy, bắt đầu/cam kết có lẽ là một ý tưởng tốt. Tất nhiên, nếu bản gốc của db không được sửa đổi (tôi thành thật không nhìn) thì không cần thiết cho điều đó ngay cả. Nếu có lỗi, bạn có thể chỉ cần xóa phần đầu ra và bắt đầu lại.

Nó cũng cung cấp tăng tốc bởi vì mọi thay đổi không phải được ghi vào đĩa khi nó xảy ra. Chúng có thể được lưu trữ trong bộ nhớ và được viết với số lượng lớn. Nhưng như đã đề cập, sqlite3 sẽ xử lý việc này cho bạn.

Ngoài ra, nó là đáng nói đến là

cmd = "attach \"%s\" as toMerge" % "b.db" 

là sai theo nghĩa là nó depracated. Nếu bạn muốn làm điều sai chính xác, đó là

cmd = 'attach "{0}" as toMerge'.format("b.db") #why not just one string though? 

Đây là tương thích về phía trước với các phiên bản mới hơn của python sẽ làm cho mã chuyển dễ dàng hơn.

nếu bạn muốn làm đúng điều, đó là

cmd = "attach ? as toMerge" 
cursor.execute(cmd, ('b.db',)) 

Điều này tránh sql injection và là, rõ ràng, hơi nhanh hơn vì vậy nó win-win.

Bạn có thể thay đổi phương pháp runCommand của bạn như sau:

def runCommand(self, sql, params=(), commit=True): 
    self.cursor.execute(sql, params) 
    if commit: 
     self.connector.commit() 

bây giờ bạn không thể cam kết sau mỗi lệnh duy nhất bằng cách thông qua commit=False khi bạn không cần một cam kết. Điều này bảo tồn khái niệm giao dịch.

+0

@prosseek có vẻ như phương thức 'thực thi' của con trỏ không thể thực thi câu lệnh 'cam kết'. Đây không phải là vấn đề lớn vì bạn chỉ có thể sử dụng phương thức 'commit' trên đối tượng connection. – aaronasterling

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