Je démarre une nouvelle application et cherche à utiliser un ORM - en particulier, SQLAlchemy.
Disons que j'ai une colonne «foo» dans ma base de données et que je souhaite l'incrémenter. En simple sqlite, c'est facile:
db = sqlite3.connect('mydata.sqlitedb')
cur = db.cursor()
cur.execute('update table stuff set foo = foo + 1')
J'ai trouvé l'équivalent 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)
C'est légèrement plus lent, mais il n'y a pas grand-chose dedans.
Voici ma meilleure estimation pour une approche 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()
Cela fait la bonne chose, mais cela prend un peu moins de cinquante fois plus longtemps que les deux autres approches. Je suppose que c'est parce qu'il doit mettre toutes les données en mémoire avant de pouvoir fonctionner avec.
Existe-t-il un moyen de générer le SQL efficace en utilisant l'ORM de SQLAlchemy? Ou en utilisant un autre ORM python? Ou devrais-je simplement revenir à l'écriture manuelle du SQL?
la source
Réponses:
L'ORM de SQLAlchemy est destiné à être utilisé avec la couche SQL, pas à la cacher. Mais vous devez garder une ou deux choses à l'esprit lorsque vous utilisez l'ORM et le SQL brut dans la même transaction. Fondamentalement, d'un côté, les modifications de données ORM n'atteindront la base de données que lorsque vous supprimerez les modifications de votre session. De l'autre côté, les instructions de manipulation de données SQL n'affectent pas les objets qui se trouvent dans votre session.
Donc si tu dis
il fera ce qu'il dit, va chercher tous les objets de la base de données, modifie tous les objets et puis quand il est temps de vider les modifications de la base de données, met à jour les lignes une par une.
Au lieu de cela, vous devriez faire ceci:
Cela s'exécutera comme une requête comme vous vous en doutez, et comme au moins la configuration de session par défaut expire toutes les données de la session lors de la validation, vous n'avez aucun problème de données périmées.
Dans la série 0.5 presque sortie, vous pouvez également utiliser cette méthode pour la mise à jour:
Cela exécutera essentiellement la même instruction SQL que l'extrait de code précédent, mais sélectionnera également les lignes modifiées et expirera toutes les données périmées de la session. Si vous savez que vous n'utilisez aucune donnée de session après la mise à jour, vous pouvez également ajouter
synchronize_session=False
à l'instruction de mise à jour et supprimer cette sélection.la source
Essayez ceci =)
la source
json
colonneIl existe plusieurs façons de METTRE À JOUR à l'aide de sqlalchemy
la source
Voici un exemple de résolution du même problème sans avoir à mapper les champs manuellement:
Donc, pour mettre à jour une instance Media, vous pouvez faire quelque chose comme ceci:
la source
Sans tests, j'essaierais:
(IIRC, commit () fonctionne sans flush ()).
J'ai constaté que parfois, faire une grande requête puis itérer en python peut être jusqu'à 2 ordres de grandeur plus rapide que de nombreuses requêtes. Je suppose que l'itération sur l'objet de requête est moins efficace que l'itération sur une liste générée par la méthode all () de l'objet de requête.
[Veuillez noter le commentaire ci-dessous - cela n'a pas du tout accéléré les choses].
la source
Si c'est à cause de la surcharge en termes de création d'objets, alors il ne peut probablement pas être accéléré du tout avec SA.
Si c'est parce qu'il charge des objets associés, vous pourrez peut-être faire quelque chose avec le chargement différé. Y a-t-il beaucoup d'objets créés en raison de références? (IE, l'obtention d'un objet Company obtient également tous les objets People associés).
la source