Ошибка ввода-вывода при записи в базу данных SQL - PullRequest
1 голос
/ 13 апреля 2019

У меня есть база данных, в которую я вставляю строки и заполняю их значениями.В настоящее время я использую sqlite3 на Python 3. Меня удивляет то, что, если я просто вставлю строки / значения вручную по одной (например, iterations = 1), это будет работать.Кроме того, если я просто оставлю iterations ниже (приблизительно) 100, это тоже будет работать!Но по мере того, как я увеличиваю количество итераций, появляется некоторое количество случайно изменяющихся (обычно менее 1000) итераций, которое я по какой-то причине не могу превышать, и я наблюдаю, как ошибка каждый раз копируется ниже.

Что вызывает эту ошибку?Как это можно преодолеть, чтобы я мог сделать iterations настолько большим, насколько это необходимо (например, 1000000)?Ниже приведен небольшой упрощенный фрагмент кода большего размера:


column1 = 'id'
column2 = 'shot'
column3 = 'time'
column4 = 'psi'
column5 = 'temp'
column6 = 'dens'
column7 = 'temp_err'
column8 = 'dens_err'
iterations = 1000
timeout = 100
i = 0 
while i < iterations:
    try:  
        time = 3
        psi = 2 
        unique_id = 232
        temp = 0.4
        dens = 0.2
        temp_err = 0.02
        dens_err = 0.01
        values = [str(unique_id),str(shot),time,psi,temp,dens,temp_err,dens_err]
        conn = sqlite3.connect(sqlite_file,timeout=timeout)
        cursor = conn.cursor()
        cursor.execute("INSERT INTO {tn} ({c1},{c2},{c3},{c4},{c5},{c6},{c7},{c8}) VALUES ({o1},{o2},{o3},{o4},{o5},{o6},{o7},{o8})".\
                    format(tn=table_name,c1=column1,c2=column2,c3=column3,c4=column4,c5=column5,c6=column6,c7=column7,c8=column8,o1=values[0],\
                           o2=values[1],o3=values[2],o4=values[3],o5=values[4],o6=values[5],o7=values[6],o8=values[7]))
        conn.commit() 
        conn.close() 
    except sqlite3.IntegrityError:
        print('ERROR: ID already exists in PRIMARY KEY column {}'.format(column1)) 
    i = i + 1    

Наблюдаемая мной ошибка:

Traceback (most recent call last):

  File "<ipython-input-27-59d2691987a1>", line 18, in <module>
    o2=values[1],o3=values[2],o4=values[3],o5=values[4],o6=values[5],o7=values[6],o8=values[7]))

OperationalError: disk I/O error

Я пытался увеличить timeout и подключить /фиксация / закрытие соединения с базой данных вне цикла, но эти подходы не сработали.


Еще одно возможное решение, которое сработало для меня:

column1 = 'id'
column2 = 'shot'
column3 = 'time'
column4 = 'psi'
column5 = 'temp'
column6 = 'dens'
column7 = 'temp_err'
column8 = 'dens_err'
iterations = 10000
timeout = 100 
with sqlite3.connect(sqlite_file,timeout=timeout) as conn:
    cursor = conn.cursor()
    i = 0 
    while i < iterations:
        try:  
            time = 3
            psi = 2 
            unique_id = 232
            temp = 0.4
            dens = 0.2
            temp_err = 0.02
            dens_err = 0.01
            values = [str(unique_id),str(shot),time,psi,temp,dens,temp_err,dens_err]
            cursor.execute("INSERT INTO {tn} ({c1},{c2},{c3},{c4},{c5},{c6},{c7},{c8}) VALUES ({o1},{o2},{o3},{o4},{o5},{o6},{o7},{o8})".\
                        format(tn=table_name,c1=column1,c2=column2,c3=column3,c4=column4,c5=column5,c6=column6,c7=column7,c8=column8,o1=values[0],\
                               o2=values[1],o3=values[2],o4=values[3],o5=values[4],o6=values[5],o7=values[6],o8=values[7]))
        except sqlite3.IntegrityError:
            print('ERROR: ID already exists in PRIMARY KEY column {}'.format(column1)) 
        i = i + 1  
        print(i)
    conn.commit()  

1 Ответ

1 голос
/ 13 апреля 2019

Как база данных настроена на диске? Возможно, накопитель переполнен и больше не может записывать, или у вашей системы проблемы с обработкой пропускной способности.

Проверьте, не заполнен ли диск sqlite3, и, если нет, попробуйте добавить небольшую задержку между вставками. В качестве альтернативы, вы можете попробовать предварительно рассчитать все данные, которые вы хотите вставить, и запустить одну большую массовую вставку, а не несколько маленьких.

Это не должно относиться к вашему коду Python и многим другим вопросам, связанным с sqlite3 / hardware.

Редактировать

Согласно комментарию @Jonathan Willcock, вы также можете попробовать обернуть все вставки в одну транзакцию.

Чтобы сделать это, вам придется перетасовать некоторые вещи вокруг. Предполагается, что поток будет таким:

open connection > start transaction > run queries > commit transaction on success / rollback transaction on error > close connection

try:
    conn = sqlite3.connect(sqlite_file, timeout=timeout, isolation_level=None)
    cursor = conn.cursor()
    while i < iterations:
        # your loop here
    conn.commit()
except sqlite3.IntegrityError:
    conn.rollback()
    # other error handling here
finally:
    conn.close()
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...