【问题标题】:peewee vs sqlalchemy performancepeewee vs sqlalchemy 性能
【发布时间】:2016-08-25 02:51:05
【问题描述】:

我有 2 个简单的脚本:

from sqlalchemy import create_engine, ForeignKey, Table
from sqlalchemy import Column, Date, Integer, String, DateTime, BigInteger, event
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.engine import Engine
from sqlalchemy.orm import relationship, backref, sessionmaker, scoped_session, Session

class Test(declarative_base()):
    __tablename__ = "Test"
    def __init__(self, *args, **kwargs):
        args = args[0]
        for key in args:
            setattr(self, key, args[key] )
    key = Column(String, primary_key=True)

data = []
for a in range(0,10000):
    data.append({ "key" : "key%s" % a})


engine = create_engine("sqlite:///testn", echo=False)
with engine.connect() as connection:
    Test.metadata.create_all(engine)
    session = Session(engine)
    list(map(lambda x: session.merge(Test(x)), data))
    session.commit()

结果:

real    0m15.300s
user    0m14.920s
sys     0m0.351s

第二个脚本:

from peewee import *

class Test(Model):
    key = TextField(primary_key=True,null=False)

dbname = "test"
db = SqliteDatabase(dbname)
Test._meta.database = db
data = []
for a in range(0,10000):
    data.append({ "key" : "key%s" % a })

if not Test.table_exists():
    db.create_tables([Test])
with db.atomic() as tr:
        Test.insert_many(data).upsert().execute()

结果:

real    0m3.253s
user    0m2.620s
sys     0m0.571s

为什么?

【问题讨论】:

  • 这 10000 次合并将使 10000 次访问数据库。
  • 这些根本没有可比性。您正在将橘子与摩天大楼进行比较。

标签: python sqlalchemy peewee


【解决方案1】:

这种比较并不完全有效,因为发出 upsert 样式的查询与 SQLAlchemy 的 Session.merge 所做的非常不同:

Session.merge() 检查源实例的主键属性,并尝试将其与会话中相同主键的实例进行协调。如果在本地找不到,它会尝试根据主键从数据库中加载对象,如果找不到,则创建一个新实例。

在这个测试用例中,这将导致对数据库进行 10,000 次加载尝试,这很昂贵。

另一方面,当使用 peewee 和 sqlite 时,insert_many(data)upsert() 的组合可能会导致单个查询:

INSERT OR REPLACE INTO Test (key) VALUES ('key0'), ('key1'), ...

没有要协调的会话状态,因为 peewee 是一种与 SQLAlchemy 非常不同的 ORM,并且快速浏览看起来更接近 CoreTables

在 SQLAlchemy 而不是 list(map(lambda x: session.merge(Test(x)), data)) 中,您可以恢复使用 Core:

session.execute(Test.__table__.insert(prefixes=['OR REPLACE']).values(data))

这方面的一个主要缺点是您必须手动将数据库供应商特定的前缀写入INSERT。这也会破坏 Session,因为它不会有关于新添加的行的信息或知识。

使用模型对象的批量插入是little more involved with SQLAlchemy。很简单地说,使用 ORM 是在易用性和速度之间进行权衡:

ORM 基本上不适用于高性能批量插入 - 这就是 SQLAlchemy 除了 ORM 之外还提供 Core 作为一流组件的全部原因。

【讨论】:

    猜你喜欢
    • 2011-08-24
    • 2010-11-09
    • 1970-01-01
    • 2012-03-17
    • 1970-01-01
    • 2013-08-25
    • 2021-02-27
    • 2013-10-18
    • 1970-01-01
    相关资源
    最近更新 更多