【问题标题】:PonyORM, SQLite performancePonyORM、SQLite 性能
【发布时间】:2016-03-08 22:09:26
【问题描述】:

我在 Raspberry PI 3 上使用 PonyORM 作为我的 SQLite 数据库的 ORM 和 Python 3.5(不是你能想象到的最快的设备,但它不应该那么糟糕)。

某些操作,例如插入,似乎非常慢。一次插入包含 3 个短字符串的实体可能需要 4 - 10 秒。

这是我的 datamodel.py 文件:

from pony.orm import *
from datetime import datetime

db = Database('sqlite', 'website.db', create_db = True)

class User(db.Entity):
    login = Required(str, unique=True)
    password = Required(str)
    actions = Set("Event")

class Event(db.Entity):
    description = Optional(str)
    date = Required(datetime)
    ip = Required(str)
    user = Optional(User)

db.generate_mapping(create_tables = True)

我还创建了一个非常简单的性能测试:

from datamodel import *
from datetime import *

sql_debug(True)
totalTime = datetime.now()
with db_session:
    constructTime = datetime.now()
    Event(date = datetime.now(),
          ip = '0.0.0.0',
          description = 'Sample event!')
    constructTime = datetime.now() - constructTime
totalTime = datetime.now() - totalTime
print(constructTime)
print(totalTime)

它的样本结果:

GET NEW CONNECTION
BEGIN IMMEDIATE TRANSACTION
INSERT INTO "Event" ("description", "date", "ip", "classtype") VALUES (?, ?, ?, ?)
['Sample event!', '2016-03-08 23:05:15.066742', '0.0.0.0', 'Event']

COMMIT
RELEASE CONNECTION
0:00:00.000479
0:00:04.808138

SQL 查询字符串打印得很快,所以我猜这里的翻译不是问题,但是正如你所看到的,整个操作需要几秒钟。

这可能是什么原因?有什么办法可以改善这个荒谬的长时间吗?

【问题讨论】:

  • 自行实现的时序算法不是可靠的数据点。
  • @cricket_007 你是否认为我的时间测量方法不好?好吧,也许您是对的,也许它不准确,但是无论如何,当它冻结几秒钟以将数据插入数据库时​​,实际应用中就会出现问题。
  • 我只是说在一台计算机上进行多次有限的运行并不是很可靠,因为声称存在很大的速度差异。不过,ORM 通常比原始查询慢得多。
  • @cricket_007 我并不是说 ORM 和原始查询之间存在或没有区别,我还没有测试过。有问题的 SQL 查询是由 ORM 生成的输出,它在启动程序后可能不到一秒钟就出现在屏幕上,但这只是我的观察,我不知道如何在 Python 中测量。
  • 好吧,您的totalTime 包括打开和关闭db_session 资源并进行一些日期数学运算的时间(并不是那些很慢)。我想你看到的高是打开、插入和关闭操作加在一起

标签: python sqlite ponyorm


【解决方案1】:

我认为问题是由慢速 SD 卡引起的。在COMMIT 执行期间,SQLite 将数据刷新到卡中,此操作对于 SD 卡可能会很慢。 SQLite 在 Raspberry PI 上运行缓慢是一个已知问题,尤其是在卡类低于 10 类的情况下:https://spin.atomicobject.com/2013/11/14/sqlite-raspberry-pi/

您可以执行以下测试以检查 PonyORM 在您的情况下是否对速度慢负责:

1) 尝试使用内存数据库。为此,请将带有数据库对象定义的行替换为以下行:

db = Database('sqlite', ':memory:', create_db=True)

2) 不使用 PonyORM 执行相同的操作。我保留prints 以​​检查它们是否不是缓慢的原因:

import sqlite3
from datetime import *

totalTime = datetime.now()
connection = sqlite3.connect('website.db', isolation_level=None)

sql = 'BEGIN IMMEDIATE TRANSACTION'
print(sql)
connection.execute(sql)

sql = 'INSERT INTO "Event" ("description", "date", "ip", "classtype") VALUES (?, ?, ?, ?)'
args = ('Sample event!', '2016-03-08 23:05:15.066742', '0.0.0.0', 'Event')
print(sql)
print(args)
connection.execute(sql, args)

sql = 'COMMIT'
print(sql)
connection.execute(sql)

totalTime = datetime.now() - totalTime
print(totalTime)

如果性能问题是由 SD 卡引起的,第一次测试会立即执行,第二次测试会和 ORM 一样慢。

也许可以通过使用 SQLite pragmas PRAGMA synchronous = OFF and PRAGMA journal_mode = MEMORY 来获得更好的性能。目前 PonyORM 不提供自动设置这些选项的方法,因为这些选项可能会因突然断电而损坏数据库文件。

【讨论】:

  • 我已经自己进行了类似的测试,甚至在你回答之前。插入在内存模式下很快,即使在将原始 SQL 查询与文件中的数据库一起使用时仍然非常慢。我尝试将数据库文件移动到 pendrive,它显着改善了插入时间,现在需要 100-500 毫秒。所以你对 SD 卡的看法是对的,但这让我有点惊讶,因为数据库文件很小,写一个比它大 10 倍的文件也只需要几毫秒。无论如何,这肯定不是 PonyORM 的错 - 感谢您开发如此优秀且用户友好的软件!
猜你喜欢
  • 1970-01-01
  • 2011-10-27
  • 1970-01-01
  • 2013-02-12
  • 2016-10-08
  • 2013-03-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多