sqlite 如何在 flask 或瓶子应用程序中高效地提交数据库更改?

dba5bblo  于 2023-02-23  发布在  SQLite
关注(0)|答案(2)|浏览(232)

我注意到SQLite db.commit()(保存到磁盘)在我的小数据库中花费了50 ms到100 ms。这是正常的,并且在这里进行了记录,但是在客户端的每个请求之后/在每个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 ms),如果因为数据库提交而损失100 ms,那将是一种耻辱。
当然,我可以启动一个新线程,每10秒调用worker()一次(在最坏的情况下,如果应用程序崩溃,只有最后10秒的数据库会丢失),但我读到不建议在这种情况下使用线程。

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

t30tvxxf

t30tvxxf1#

你可以写一个Flask after_request()处理程序并在那里提交数据库,你甚至可以限制只在自上次提交以来已经过了一定的时间之后才这样做。
这不会阻止您的请求,也不会太频繁地保存文件。

wz1wpwve

wz1wpwve2#

这里是一个尝试,如果在这个时间段内有一个INSERT,它每10秒才提交一次。
注意:它需要check_same_thread=False,如ProgrammingError: SQLite objects created in a thread can only be used in that same thread中所述。

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

这将性能提高了至少一个数量级。
有用资源:

相关问题