Python,SQLAlchemy:如何提高加密的sqlite数据库的性能?

时间:2018-10-24 18:52:39

标签: python sqlalchemy tornado

我有一个简单的服务应用程序:python,龙卷风Web服务器,sqlite数据库。数据库已加密。

问题在于,即使处理非常简单的http请求也要花费大约300毫秒。

从日志中我可以看到,无论第一个请求多么简单,大部分时间都需要处理第一个sql请求。后续sql请求的处理速度更快。但是随后服务器开始处理下一个http请求,并且第一个sql请求又很慢。

如果我关闭数据库加密,问题就不存在了:sql请求的处理时间不取决于请求是否是第一个,并且我的服务器响应时间减少了10到15。

我不太了解发生了什么。看起来sqlalchemy每次启动新会话时都会读取并解密数据库文件。有什么办法可以解决此问题?

2 个答案:

答案 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/