SQLAlchemy ORM을 사용하여 데이터베이스를 효율적으로 업데이트
저는 새로운 애플리케이션을 시작하고 ORM, 특히 SQL 화학을 사용하려고 합니다.
예를 들어 데이터베이스에 'foo' 열이 있는데 이 열을 증분하려고 합니다.straight 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)
이것은 조금 느리지만, 별로 들어있지 않습니다.
SQL 화학 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을 작성해야 합니까?
SQL Lchemy의 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_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(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()
다음은 필드를 수동으로 매핑하지 않고 동일한 문제를 해결하는 방법의 예입니다.
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()
객체 생성 측면에서 오버헤드 때문이라면 SA로는 전혀 속도를 낼 수 없을 것입니다.
관련 개체를 로드하기 때문에 로드가 느리면 로드 작업을 수행할 수 있습니다.참조로 인해 많은 개체가 생성되고 있습니까? (즉, 회사 개체를 가져오면 관련된 모든 사용자 개체도 가져옵니다.)
철저한 테스트를 통해, 저는 다음을 시도할 것입니다.
for c in session.query(Stuff).all():
c.foo = c.foo+1
session.commit()
(IIRC, commit()는 플러시() 없이 작동합니다.
저는 때때로 큰 쿼리를 수행한 다음 파이썬에서 반복하는 것이 많은 쿼리보다 최대 2배 더 빠를 수 있다는 것을 발견했습니다.쿼리 개체를 반복하는 것이 쿼리 개체의 all() 메서드에서 생성된 목록을 반복하는 것보다 효율성이 떨어집니다.
[아래 설명에 유의하십시오. 이는 작업 속도를 전혀 높이지 않았습니다.
언급URL : https://stackoverflow.com/questions/270879/efficiently-updating-database-using-sqlalchemy-orm
'programing' 카테고리의 다른 글
| Firestore에서 json 내보내기 (0) | 2023.07.18 |
|---|---|
| try/catch를 사용하지 않고 Python Enum에 int 값이 있는지 테스트하려면 어떻게 해야 합니까? (0) | 2023.07.18 |
| 왜 그들은 px대신에? (0) | 2023.07.18 |
| 그룹화된 다중 막대 그림 표시 방법 (0) | 2023.07.18 |
| pip 설치: 해당 디렉터리의 권한 및 소유자를 확인하십시오. (0) | 2023.07.18 |