Rozpoczynam nową aplikację i patrzę na użycie ORM - w szczególności SQLAlchemy.
Powiedzmy, że mam kolumnę „foo” w mojej bazie danych i chcę ją zwiększyć. W prostym sqlite jest to łatwe:
db = sqlite3.connect('mydata.sqlitedb')
cur = db.cursor()
cur.execute('update table stuff set foo = foo + 1')
Znalazłem odpowiednik 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)
To jest nieco wolniejsze, ale nie ma w nim dużo.
Oto moje najlepsze przypuszczenie dotyczące podejścia 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()
Robi to dobrze, ale trwa to niecałe pięćdziesiąt razy dłużej, niż zbliżają się pozostałe dwa. Przypuszczam, że dzieje się tak dlatego, że musi przenieść wszystkie dane do pamięci, zanim będzie mógł z nimi pracować.
Czy istnieje sposób na wygenerowanie wydajnego kodu SQL przy użyciu ORM SQLAlchemy? Lub używasz innego ORM Pythona? A może powinienem po prostu wrócić do ręcznego pisania SQL?
python
orm
sqlalchemy
John Fouhy
źródło
źródło
Odpowiedzi:
ORM SQLAlchemy ma być używany razem z warstwą SQL, a nie ją ukrywać. Ale musisz pamiętać o jednej lub dwóch rzeczach, gdy używasz ORM i zwykłego SQL w tej samej transakcji. Zasadniczo z jednej strony modyfikacje danych ORM trafią do bazy danych tylko wtedy, gdy opróżnisz zmiany z sesji. Z drugiej strony, instrukcje manipulacji danymi SQL nie wpływają na obiekty w sesji.
Więc jeśli powiesz
zrobi to, co mówi, pobierze wszystkie obiekty z bazy danych, zmodyfikuje wszystkie obiekty, a kiedy nadejdzie czas, aby opróżnić zmiany w bazie danych, zaktualizuje wiersze jeden po drugim.
Zamiast tego powinieneś zrobić to:
Spowoduje to wykonanie jako jedno zapytanie, tak jak można się spodziewać, a ponieważ przynajmniej domyślna konfiguracja sesji powoduje wygaśnięcie wszystkich danych w sesji po zatwierdzeniu, nie ma żadnych starych problemów z danymi.
W prawie wydanej serii 0.5 możesz również użyć tej metody do aktualizacji:
To w zasadzie uruchomi tę samą instrukcję SQL, co poprzedni fragment kodu, ale także wybierze zmienione wiersze i wygaśnie wszystkie nieaktualne dane w sesji. Jeśli wiesz, że po aktualizacji nie używasz żadnych danych sesji, możesz również dodać
synchronize_session=False
do instrukcji aktualizacji i pozbyć się tego wyboru.źródło
Spróbuj tego =)
źródło
json
kolumnyIstnieje kilka sposobów na AKTUALIZACJĘ przy użyciu narzędzia sqlalchemy
źródło
Oto przykład, jak rozwiązać ten sam problem bez konieczności ręcznego mapowania pól:
Aby zaktualizować instancję Media, możesz zrobić coś takiego:
źródło
Po trudnych testach spróbuję:
(IIRC, commit () działa bez flush ()).
Zauważyłem, że czasami wykonanie dużego zapytania, a następnie iteracja w Pythonie może być do 2 rzędów wielkości szybsza niż wiele zapytań. Zakładam, że iteracja po obiekcie zapytania jest mniej wydajna niż iteracja po liście wygenerowanej przez metodę all () obiektu zapytania.
[Proszę zanotować komentarz poniżej - to wcale nie przyspieszyło sprawy].
źródło
Jeśli jest to spowodowane narzutem związanym z tworzeniem obiektów, prawdopodobnie nie można go w ogóle przyspieszyć za pomocą SA.
Jeśli dzieje się tak, ponieważ ładuje powiązane obiekty, możesz być w stanie zrobić coś z ładowaniem z opóźnieniem. Czy na podstawie odniesień powstaje wiele obiektów? (IE, zdobycie obiektu firmy powoduje również pobranie wszystkich powiązanych obiektów People).
źródło