我有一个简单的服务应用程序:python,龙卷风Web服务器,sqlite数据库。数据库已加密。
问题在于,即使处理非常简单的http请求也要花费大约300毫秒。
从日志中我可以看到,无论第一个请求多么简单,大部分时间都需要处理第一个sql请求。后续sql请求的处理速度更快。但是随后服务器开始处理下一个http请求,并且第一个sql请求又很慢。
如果我关闭数据库加密,问题就不存在了:sql请求的处理时间不取决于请求是否是第一个,并且我的服务器响应时间减少了10到15。
我不太了解发生了什么。看起来sqlalchemy每次启动新会话时都会读取并解密数据库文件。有什么办法可以解决此问题?
答案 0 :(得分:5)
由于pysqlite或sqlite3
模块如何运行SQLAlchemy defaults to using a NullPool
with file-based databases。这就解释了为什么每个请求都会解密数据库:NullPool
在连接关闭时会丢弃它们。这样做的原因是pysqlite的默认行为是禁止在多个线程中使用连接,并且无需加密即可快速创建新连接。
Pysqlite确实有一个未记录的标志check_same_thread
,可用来禁用该检查,但是应谨慎处理线程之间的共享连接,并且SQLAlchemy文档还提到NullPool
很好地起作用使用SQLite的文件锁定。
根据您的Web服务器,您可以使用SingletonThreadPool
,这意味着线程中的所有连接都是相同的连接:
engine = create_engine('sqlite:///my.db',
poolclass=SingletonThreadPool)
如果您觉得冒险,并且Web服务器在使用中(例如,使用作用域的会话)在线程之间不共享连接/会话,那么您可以尝试使用与check_same_thread=False
配对的不同池化策略:>
engine = create_engine('sqlite:///my.db',
poolclass=QueuePool,
connect_args={'check_same_thread':False})
答案 1 :(得分:0)
要加密数据库sqlcipher,请使用我提供的密码创建一个密钥。此操作在设计上很消耗资源。
但是可以使用不是密码短语,而是使用256位原始密钥。在这种情况下,sqlcipher不必生成加密密钥。
最初我的代码是:
session.execute('PRAGMA KEY = "MY_PASSPHRASE";')
要使用原始密钥,我将此行更改为:
session.execute('''PRAGMA KEY = "x'<the key>'";''')
其中<the key>
是64个字符的十六进制长字符串。
小请求的结果是20倍以上。
仅供参考:要转换数据库以使用新的加密密钥,应执行以下命令:
PRAGMA KEY = ""MY_PASSPHRASE";
PRAGMA REKEY = "x'<the key>'";
相关问题:python, sqlite, sqlcipher: very poor performance processing first request
有关sqlcipher命令的一些信息以及键和原始键之间的区别:https://www.zetetic.net/sqlcipher/sqlcipher-api/