Объедините файлы SQLite в один файл БД и задайте вопрос «начать / зафиксировать» - PullRequest
5 голосов
/ 11 сентября 2010

Этот пост ссылается на эту страницу для объединения баз данных SQLite.

Последовательность следующая.Допустим, я хочу объединить a.db и b.db.В командной строке я делаю следующее.

  • sqlite3 a.db
  • присоединить 'b.db' как toM;
  • начало;<- </li>
  • вставить в бенчмарк select * from toM.benchmark;
  • commit;<- </li>
  • отсоединить базу данных от M;

Работает хорошо, но на указанном сайте спрашивающий спрашивает об ускорении, и ответом является использование «begin» икоманда 'commit'.

Затем я придумал следующий код на python, чтобы сделать то же самое.Я абстрагирую вызовы функций SQLite с помощью SQLiteDB, и одним из методов является runCommand ().Я получил ту же ошибку, хотя я удаляю 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)

Но я получил следующую ошибку.

OperationalError: cannot commit - no transaction is active

Даже если ошибка,Результат БД хорошо слит.А без начала / коммита нет ошибки вообще.

  • Почему я не могу запустить команду begin / commit?
  • Обязательно ли запускать start / commit для безопасного объединения файлов БД?В посте говорится, что цель begin / commit - это ускорение.Тогда какая разница между использованием и отсутствием команды begin / commit с точки зрения ускорения?

1 Ответ

12 голосов
/ 11 сентября 2010

Очевидно, Cursor.execute не поддерживает команду 'commit'. Он поддерживает команду 'begin', но это избыточно, потому что sqlite3 начинает их для вас в любом случае:

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

просто используйте метод commit для вашего Connection объекта.

Что касается вашего второго вопроса, не обязательно вызывать begin / commit при объединении файлов: просто убедитесь, что нет абсолютно никаких ошибок на диске, изменений в БД или людей, которые смотрят на компьютер неправильно, когда он это происходит. Так что начать / зафиксировать это, вероятно, хорошая идея. Конечно, если исходные базы данных не модифицируются (я честно не смотрел), то в этом даже нет необходимости. Если есть ошибка, вы можете просто отказаться от частичного вывода и начать заново.

Это также обеспечивает ускорение, потому что каждое изменение не должно записываться на диск по мере его появления. Они могут быть сохранены в памяти и записаны навалом. Но, как уже упоминалось, sqlite3 обрабатывает это для вас.

Также стоит упомянуть, что

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

неверно в том смысле, что это испорчено. Если вы хотите правильно поступить неправильно, это

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

Это совместимо с новыми версиями python, что упрощает перенос кода.

если вы хотите сделать правильную вещь, это

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

Это позволяет избежать инъекций sql и, по-видимому, немного быстрее, так что это беспроигрышный вариант.

Вы можете изменить свой метод runCommand следующим образом:

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

теперь вы не можете коммитить после каждой команды, передавая commit=False, когда вам не нужен коммит. Это сохраняет понятие транзакции.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...