sqlalchemy orm을 사용하여 데이터베이스를 효율적으로 업데이트합니다

StackOverflow https://stackoverflow.com/questions/270879

  •  06-07-2019
  •  | 
  •  

문제

새로운 응용 프로그램을 시작하고 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을 생성하는 방법이 있습니까? 아니면 다른 파이썬 ORM을 사용하십니까? 아니면 수작업으로 SQL을 쓰는 것으로 돌아가야합니까?

도움이 되었습니까?

해결책

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()

이것은 예상대로 하나의 쿼리로 실행되며, 적어도 기본 세션 구성은 Commit에서 세션의 모든 데이터를 만료하기 때문에 오래된 데이터 문제가 없습니다.

거의 출시 된 0.5 시리즈에서는이 방법을 사용하여 업데이트 할 수도 있습니다.

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

기본적으로 이전 스 니펫과 동일한 SQL 문을 실행하지만 변경된 행을 선택하고 세션에서 오래된 데이터를 만료합니다. 업데이트 후 세션 데이터를 사용하지 않는다는 것을 알고 있다면 Synchronize_Session = False를 업데이트 문에 추가하고 해당 선택을 제거 할 수도 있습니다.

다른 팁

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

이것을 시도 =)

sqlalchemy를 사용하여 업데이트하는 몇 가지 방법이 있습니다

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

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

3) conn = engine.connect()
   stmt = Stuff.update().\
       values(Stuff.foo = (Stuff.foo + 1))
   conn.execute(stmt)

다음은 필드를 수동으로 매핑하지 않고도 동일한 문제를 해결하는 방법의 예입니다.

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()

테스트를 통해 시도해 볼 것입니다.

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

(IIRC, Commit ()는 flush ()없이 작동합니다.

때때로 큰 쿼리를 수행 한 다음 파이썬으로 반복하는 것이 많은 쿼리보다 최대 2 배 더 빠를 수 있음을 발견했습니다. 쿼리 객체를 반복하는 것이 쿼리 객체의 모든 () 메소드에 의해 생성 된 목록을 반복하는 것보다 덜 효율적이라고 가정합니다.

아래 의견에 주목하십시오 - 이것은 전혀 속도를 높이 지 않았습니다].

객체를 만드는 측면에서 오버 헤드 때문인 경우 SA와 전혀 쏟아 질 수 없습니다.

관련 객체를로드하고 있기 때문에 게으른 하중으로 무언가를 할 수 있습니다. 참조로 인해 생성되는 객체가 많이 있습니까? (즉, 회사 객체를 얻는 것은 모든 관련 인물 객체를 얻습니다).

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top