Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/306.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 使用SQLAlchemy ORM高效更新数据库_Python_Orm_Sqlalchemy - Fatal编程技术网

Python 使用SQLAlchemy ORM高效更新数据库

Python 使用SQLAlchemy ORM高效更新数据库,python,orm,sqlalchemy,Python,Orm,Sqlalchemy,我正在启动一个新的应用程序,并考虑使用ORM——特别是SQLAlchemy 假设我的数据库中有一列'foo',我想增加它。在直sqlite中,这很容易: db = sqlite3.connect('mydata.sqlitedb') cur = db.cursor() cur.execute('update table stuff set foo = foo + 1') 我找到了SQLAlchemy SQL builder的等价物: engine = sqlalchemy.create_eng

我正在启动一个新的应用程序,并考虑使用ORM——特别是SQLAlchemy

假设我的数据库中有一列'foo',我想增加它。在直sqlite中,这很容易:

db = sqlite3.connect('mydata.sqlitedb')
cur = db.cursor()
cur.execute('update table stuff set foo = foo + 1')
我找到了SQLAlchemy SQL builder的等价物:

engine = sqlalchemy.create_engine('sqlite:///mydata.sqlitedb')
md = sqlalchemy.MetaData(engine)
table = sqlalchemy.Table('stuff', md, autoload=True)
upd = table.update(values={table.c.foo:table.c.foo+1})
engine.execute(upd)
这稍微慢一点,但没有太多

以下是我对SQLAlchemy ORM方法的最佳猜测:

# snip definition of Stuff class made using declarative_base
# snip creation of session object
for c in session.query(Stuff):
    c.foo = c.foo + 1
session.flush()
session.commit()
这样做是正确的,但所需时间是其他两种方法的50倍。我想这是因为它必须先将所有数据存入内存,然后才能使用它


有没有办法使用SQLAlchemy的ORM生成高效的SQL?或者使用任何其他python ORM?或者我应该继续手工编写SQL吗?

在没有经过测试的情况下,我会尝试:

for c in session.query(Stuff).all():
     c.foo = c.foo+1
session.commit()
(IIRC,commit()在没有flush()的情况下工作)

我发现,有时在python中执行大型查询并进行迭代比执行大量查询快2个数量级。我假设迭代查询对象的效率低于迭代查询对象的all()方法生成的列表的效率


[请注意下面的评论-这根本没有加快速度]。

如果是因为创建对象的开销,那么SA可能根本无法加快速度


如果这是因为它正在加载相关的对象,那么您可能可以通过延迟加载来做一些事情。是否由于引用而创建了很多对象?(即,获取公司对象也会获取所有相关的人员对象)。

SQLAlchemy的ORM旨在与SQL层一起使用,而不是隐藏它。但是,在同一事务中使用ORM和普通SQL时,必须记住一两件事。基本上,从一方面来说,ORM数据修改只会在刷新会话中的更改时影响数据库。另一方面,SQL数据操作语句不会影响会话中的对象

所以如果你说

for c in session.query(Stuff).all():
    c.foo = c.foo+1
session.commit()
它将按照它所说的做,从数据库中获取所有对象,修改所有对象,然后在刷新对数据库的更改时,逐个更新行

相反,您应该这样做:

session.execute(update(stuff_table, values={stuff_table.c.foo: stuff_table.c.foo + 1}))
session.commit()
这将像您所期望的那样作为一个查询执行,并且因为至少默认会话配置在提交时会使会话中的所有数据过期,所以您没有任何过时的数据问题

在即将发布的0.5系列中,您也可以使用此方法进行更新:

session.query(Stuff).update({Stuff.foo: Stuff.foo + 1})
session.commit()
这将基本上运行与前一个代码段相同的SQL语句,但也会选择更改的行并使会话中的任何过时数据过期。如果您知道在更新之后没有使用任何会话数据,您还可以将
synchronize\u session=False
添加到update语句中,并删除该选择

session.query(Clients).filter(Clients.id == client_id_list).update({'status': status})
session.commit()

试试这个=)

下面是一个示例,说明如何在不必手动映射字段的情况下解决相同的问题:

from sqlalchemy import Column, ForeignKey, Integer, String, Date, DateTime, text, create_engine
from sqlalchemy.exc import IntegrityError
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker
from sqlalchemy.orm.attributes import InstrumentedAttribute

engine = create_engine('postgres://postgres@localhost:5432/database')
session = sessionmaker()
session.configure(bind=engine)

Base = declarative_base()


class Media(Base):
  __tablename__ = 'media'
  id = Column(Integer, primary_key=True)
  title = Column(String, nullable=False)
  slug = Column(String, nullable=False)
  type = Column(String, nullable=False)

  def update(self):
    s = session()
    mapped_values = {}
    for item in Media.__dict__.iteritems():
      field_name = item[0]
      field_type = item[1]
      is_column = isinstance(field_type, InstrumentedAttribute)
      if is_column:
        mapped_values[field_name] = getattr(self, field_name)

    s.query(Media).filter(Media.id == self.id).update(mapped_values)
    s.commit()
因此,要更新媒体实例,可以执行以下操作:

media = Media(id=123, title="Titular Line", slug="titular-line", type="movie")
media.update()

有几种方法可以使用sqlalchemy进行更新

1) for c in session.query(Stuff).all():
       c.foo += 1
   session.commit()

2) session.query(Stuff).update({"foo": Stuff.foo + 1})
   session.commit()

3) conn = engine.connect()
   table = Stuff.__table__
   stmt = table.update().values({'foo': Stuff.foo + 'a'})
   conn.execute(stmt)
   conn.commit()

添加.all()和删除.flush()完全没有改变时间。不,表是独立的。我以前从未使用过ORM——这只是他们不擅长的事情吗?创建对象会带来开销,但在我看来这是值得的——能够在数据库中持久存储对象是很棒的。好吧,我假设答案是“这不是ORM擅长的事情”。哦,好吧;我生活和学习。有一些实验在不同的orm上运行,以及它们在负载和胁迫下的表现。没有现成的链接,但值得一读。上一个(ORM)示例存在的另一个问题是它不是。这个方法对我很有效。但问题是速度太慢。对于一些100k的数据记录,它需要一段很长的时间。可能有更快的方法吗?非常感谢这种方法对我有效。对于那些在使用此方法时仍然存在性能问题的人来说,sqlachemy没有更短的方法来更新
json
列,这真是太糟糕了:默认情况下,这可能会先对每个记录进行选择,然后才进行更新。将synchronize_session=False传递给update()方法可以防止这种情况发生,但请确保仅在提交()之前不使用更新的对象时才这样做。第三种方式,它是否会触发orm事件(如更新之后)?@Ken,不,不会。有关Query.update,请参见API文档。相反,您有一个用于批量更新后的事件