Python SQLite3 / Nested cursor.execute - PullRequest
       35

Python SQLite3 / Nested cursor.execute

0 голосов
/ 28 апреля 2018

Рассмотрим следующий фрагмент кода:

for count in range(28, -1, -1):
    crsr.execute("SELECT board, win1, win2 FROM positions WHERE balls = ?", (count,))
    response = crsr.fetchall()
    print count, len(response)
    for possibility in response:
        internal = possibility[0]
        player = count & 1
        victor = 1 - player
        opponent = 2 - player
        victory = possibility[opponent]
        if victory:
            crsr.execute("UPDATE positions SET result = ? WHERE board = ?", (victor, internal))
        else:
            subsequent = derive((internal, count))
            for derived in subsequent:
                external = reduce(derived[0])
                crsr.execute("SELECT result FROM positions WHERE board = ?", (external,))
                colour = crsr.fetchall()
                if colour[0][0] == player:
                    victor = player
                    break
            crsr.execute("UPDATE positions SET result = ? WHERE board = ?", (victor, internal))

Рассмотрим со строкой:

response = crsr.fetchall()

Всякий раз, когда в response содержится до 10 7 строк, приведенный выше оператор возвращает ошибку памяти даже в системе с 8 ГБ ОЗУ.

Итак, я решил, что я изменю следующий фрагмент кода:

for count in range(28, -1, -1):
    crsr.execute("SELECT board, win1, win2 FROM positions WHERE balls = ?", (count,))
    response = crsr.fetchall()
    print count, len(response)
    for possibility in response:
        internal = possibility[0]

до:

for count in range(28, -1, -1):
    crsr.execute("SELECT COUNT(board) FROM positions WHERE balls = ?", (count,))
    sum = crsr.fetchall()
    total = sum[0][0]
    print count, total
    crsr.execute("SELECT board, win1, win2 FROM positions WHERE balls = ?", (count,))
    for possibility in range(total):
        response = crsr.fetchone()
        internal = response[0]

Теперь, когда строка:

response = crsr.fetchone()

использует переменную crsr для выполнения запроса выбора SQLite3 для каждой итерации possibility в range(total).

Уже есть другие операторы crsr в том же цикле for:

crsr.execute("UPDATE positions SET result = ? WHERE board = ?", (victor, internal))

с этим утверждением, встречающимся дважды, и

crsr.execute("SELECT result FROM positions WHERE board = ?", (external,)).

с этим утверждением, встречающимся один раз.

Таким образом, всякий раз, когда переменная crsr из строки: response = crsr.fetchall() изменяется с каждой итерацией possibility в range(total), она не будет конфликтовать с другими операторами crsr, уже находящимися в том же цикле for.

Мы не можем создавать с другими переменными курсора для выполнения с другими запросами SQLite3, потому что crsr определяется с помощью crsr = connection.cursor() для конкретного файла базы данных, как только он инициализируется (в данном конкретном случае spline.db) .

Итак, я хотел бы знать, что, если есть какие-либо другие альтернативные решения, доступные для него, достаточно эффективные.

1 Ответ

0 голосов
/ 28 апреля 2018

Набор результатов является частью объекта курсора, поэтому всякий раз, когда вы вызываете execute(), любой предыдущий запрос к тому же объекту курсора отменяется. Единственный способ избежать этого - использовать fetchall() для чтения всех строк результата перед выполнением следующего запроса.

Чтобы иметь возможность выполнять несколько одновременных запросов, вы должны использовать несколько курсоров. Просто позвоните connection.cursor() несколько раз.


Обратите внимание, что вы не должны изменять таблицу, из которой вы все еще читаете (даже если вы используете несколько курсоров); измененные строки могут быть пропущены или прочитаны дважды курсором чтения. Если вы не можете использовать fetchall(), поместите результаты первого запроса во временную таблицу:

crsr1.execute("CREATE TEMP TABLE temp_pos(board, win1, win2)")

for count in ...:
    crsr1.execute("INSERT INTO temp_pos SELECT board, win1, win2 ...")

    crsr1.execute("SELECT board, win1, win2 FROM temp_pos")
    for row in crsr1:
        if ...:
            crsr2.execute("UPDATE positions ...")
        else:
            crsr2.execute("SELECT ... FROM positions ...")
            ...
    crsr1.execute("DELETE FROM temp_pos")

crsr1.execute("DROP TABLE temp_pos")
...