Ошибка операции sqlite3 при быстром выполнении многих коммитов - PullRequest
2 голосов
/ 23 октября 2009

Я получаю

sqlite3.OperationalError: SQL logic error or missing database

когда я запускаю приложение, над которым я работал. Далее следует суженный, но полный образец, который представляет проблему для меня. Этот образец использует две таблицы; один для хранения пользователей и один для записи актуальности информации о пользователях во внешней системе каталогов. (Как вы можете себе представить, таблицы в моем реальном приложении немного длиннее). Образец создает группу случайных пользователей, а затем просматривает список (случайных) пользователей и добавляет их во вторую таблицу.

#!/usr/bin/env python

import sqlite3
import random

def random_username():
    # Returns one of 10 000 four-letter placeholders for a username
    seq = 'abcdefghij'
    return random.choice(seq) + random.choice(seq) + \
           random.choice(seq) + random.choice(seq)

connection = sqlite3.connect("test.sqlite")

connection.execute('''CREATE TABLE IF NOT EXISTS "users" (
    "entry_id"              INTEGER PRIMARY KEY AUTOINCREMENT  NOT NULL ,
    "user_id"               INTEGER NOT NULL ,
    "obfuscated_name"       TEXT NOT NULL)''')
connection.execute('''CREATE TABLE IF NOT EXISTS "dir_x_user" (
    "user_id"               INTEGER PRIMARY KEY NOT NULL)''')        

# Create a bunch of random users
random.seed(0)  # get the same results every time
for i in xrange(1500):
    connection.execute('''INSERT INTO users
        (user_id, obfuscated_name) VALUES (?, ?)''',
        (i, random_username()))
connection.commit()

#random.seed()
for i in xrange(4000):
    username = random_username()
    result = connection.execute(
        'SELECT user_id FROM users WHERE obfuscated_name = ?',
        (username, ))
    row = result.fetchone()
    if row is not None:
        user_id = row[0]
        print "  %4d %s" % (user_id, username)
        connection.execute(
            'INSERT OR IGNORE INTO dir_x_user (user_id) VALUES(?)',
            (user_id, ))
    else:
        print "     ? %s" % username
    if i % 10 == 0:
        print "i = %s; committing" % i
        connection.commit()
connection.commit()

Особо следует отметить строку в конце, которая гласит:

if i % 10 == 0:

В реальном приложении я запрашиваю данные с сетевого ресурса и хочу время от времени фиксировать пользователей. Изменение этой строки изменяется при возникновении ошибки; кажется, что когда я фиксирую, существует вероятность ненулевого значения OperationalError. Похоже, это связано с данными, которые я помещаю в базу данных, но я не могу определить, в чем проблема.

В большинстве случаев, когда я читаю все данные, а затем фиксирую только один раз, ошибка не возникает. [Да, есть очевидный обходной путь, но скрытая проблема остается.]

Вот конец пробного прогона на моем компьютере:

     ? cgha
i = 530; committing
     ? gegh
     ? aabd
     ? efhe
     ? jhji
     ? hejd
     ? biei
     ? eiaa
     ? eiib
     ? bgbf
   759 bedd
i = 540; committing
Traceback (most recent call last):
  File "sqlitetest.py", line 46, in <module>
    connection.commit()
sqlite3.OperationalError: SQL logic error or missing database

Я использую Mac OS X 10.5.8 со встроенным Python 2.5.1 и Sqlite3 3.4.0.

1 Ответ

2 голосов
/ 23 октября 2009

Как следует из «облегченной» части названия, sqlite3 предназначен для легкого использования базы данных, а не для масштабируемого параллелизма, как некоторые из Big Boys. Мне кажется, что здесь происходит то, что sqlite не закончила писать последнее изменение, которое вы запросили, когда вы делаете другой запрос

Итак, некоторые варианты, которые я вижу для вас:

  1. Вы можете потратить много времени на изучение блокировки файлов, параллелизма и транзакций в sqlite3
  2. Вы можете добавить еще одну защиту от ошибок, просто приложив приложение к повторному выполнению действия после первого сбоя, как это было предложено некоторыми на в этом посте Reddit , который включает советы, такие как «Если код эффективный механизм для повторной попытки, большинство проблем параллелизма в sqlite исчезают "и" Происходит изоляция_уровня = нет подключения, кажется, это исправляет ".
  3. Вы можете переключиться на использование более масштабируемой базы данных, например PostgreSQL

(Для моих денег, путь № 2 или № 3 - это путь.)

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