如何有效地在 Flask 或 Bottle 应用程序中提交数据库更改?

How to commit DB changes in a Flask or Bottle app efficiently?

我注意到对于我的小型数据库,SQLite db.commit()(保存到磁盘)需要 50 毫秒到 100 毫秒。这是正常的 documented here,但是 在客户端的每个请求之后/在每次 INSERT 之后这样做太多了,像这样:

import bottle, sqlite3, random

@bottle.route('/')
def index():
    c = db.cursor()
    c.execute('INSERT INTO test VALUES (?)', (random.randint(0, 10000)))
    c.close()
    db.commit()    # should we do it here? (100ms is too much after *each* request!)
    return 'hello'

def worker():      
    db.commit()    # or here? how to call this worker once every 10 seconds? 

db = sqlite3.connect('test.db')
db.execute("CREATE TABLE IF NOT EXISTS test (a int)")
bottle.run(port=80)

更准确地说,我不想在每次请求后损失 100 毫秒:我优化了我的服务器以非常快地提供页面(10 毫秒),由于数据库提交而损失 100 毫秒将是一种耻辱。

当然我可以启动一个新线程每10秒调用一次worker()(在最坏的情况下,如果应用程序崩溃,只有最后10数秒的 DB 将丢失)。但我读到不建议使用 threads in this context.

问题:如何在 Bottle/Flask 网络服务器上下文中每隔几秒提交一次 SQLite 数据库(而不是每次 INSERT 后提交一次)?

您可以编写一个 Flask after_request() 处理程序并在那里提交数据库。您甚至可以限制仅在自上次提交后经过一定时间后才执行此操作。

这不会阻止您的请求,也不会过于频繁地保存文件。

这是一次尝试。如果在此时间范围内有 INSERT,它只会每 10 秒提交一次。

注意:它需要 check_same_thread=False,如 中所述。

import bottle, sqlite3, random, threading, time

@bottle.route('/')
def index():
    global committhread
    c = db.cursor()
    c.execute('INSERT INTO test VALUES (?)', (random.randint(0, 10000),))
    c.close()
    if not committhread: 
        print('Calling commit()...')
        committhread = threading.Thread(target=commit)
        committhread.start()
    else:
        print('A commit is already planned.')
    return 'hello'

def commit():
    global committhread
    print("We'll commit in 10 seconds.")
    time.sleep(10)  # I hope this doesn't block/waste CPU here?
    db.commit()
    print('Committed.')
    committhread = None    

db = sqlite3.connect('test.db', check_same_thread=False)
db.execute("CREATE TABLE IF NOT EXISTS test (a int)")
committhread = None
bottle.run(port=80)

但是正如 SQLite and Python: commit once every 10 seconds maximum, and not after every client request 中所讨论的,在执行前面的代码之前还有一些其他选项值得尝试,例如:

c.execute('PRAGMA synchronous = OFF')
c.execute('PRAGMA journal_mode = OFF')

这至少提高了一个数量级的性能。

有用的资源: