Estoy iniciando una nueva aplicación y estoy pensando en usar un ORM, en particular, SQLAlchemy.
Digamos que tengo una columna 'foo' en mi base de datos y quiero incrementarla. En sqlite simple, esto es fácil:
db = sqlite3.connect('mydata.sqlitedb')
cur = db.cursor()
cur.execute('update table stuff set foo = foo + 1')
Descubrí el equivalente del constructor SQL de SQLAlchemy:
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)
Esto es un poco más lento, pero no tiene mucho contenido.
Aquí está mi mejor suposición para un enfoque ORM de SQLAlchemy:
# 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()
Esto hace lo correcto, pero tarda menos de cincuenta veces más que los otros dos enfoques. Supongo que es porque tiene que traer todos los datos a la memoria antes de que pueda trabajar con ellos.
¿Hay alguna forma de generar el SQL eficiente usando el ORM de SQLAlchemy? ¿O usando cualquier otro ORM de Python? ¿O debería volver a escribir el SQL a mano?
python
orm
sqlalchemy
John Fouhy
fuente
fuente
Respuestas:
El ORM de SQLAlchemy está diseñado para usarse junto con la capa SQL, no para ocultarlo. Pero debe tener en cuenta una o dos cosas al usar el ORM y SQL simple en la misma transacción. Básicamente, por un lado, las modificaciones de los datos de ORM solo afectarán a la base de datos cuando elimine los cambios de su sesión. Por otro lado, las declaraciones de manipulación de datos SQL no afectan los objetos que están en su sesión.
Entonces si dices
hará lo que dice, irá a buscar todos los objetos de la base de datos, modificará todos los objetos y luego, cuando sea el momento de eliminar los cambios en la base de datos, actualizará las filas una por una.
En su lugar, debería hacer esto:
Esto se ejecutará como una consulta como es de esperar, y debido a que al menos la configuración de sesión predeterminada expira todos los datos de la sesión en la confirmación, no tiene problemas de datos obsoletos.
En la serie 0.5 casi lanzada, también puede usar este método para actualizar:
Eso básicamente ejecutará la misma declaración SQL que el fragmento anterior, pero también seleccionará las filas modificadas y expirará cualquier dato obsoleto en la sesión. Si sabe que no está usando ningún dato de sesión después de la actualización, también puede agregarlo
synchronize_session=False
a la declaración de actualización y deshacerse de esa selección.fuente
Prueba esto =)
fuente
json
columnaHay varias formas de ACTUALIZAR usando sqlalchemy
fuente
A continuación, se muestra un ejemplo de cómo resolver el mismo problema sin tener que mapear los campos manualmente:
Entonces, para actualizar una instancia de Media, puede hacer algo como esto:
fuente
Sin pruebas suficientes, intentaría:
(IIRC, commit () funciona sin flush ()).
Descubrí que, a veces, hacer una consulta grande y luego iterar en Python puede ser hasta 2 órdenes de magnitud más rápido que muchas consultas. Supongo que iterar sobre el objeto de consulta es menos eficiente que iterar sobre una lista generada por el método all () del objeto de consulta.
[Tenga en cuenta el comentario a continuación: esto no aceleró las cosas en absoluto].
fuente
Si se debe a la sobrecarga en términos de creación de objetos, entonces probablemente no se pueda acelerar en absoluto con SA.
Si es porque está cargando objetos relacionados, es posible que pueda hacer algo con la carga diferida. ¿Se están creando muchos objetos debido a las referencias? (Es decir, obtener un objeto Company también obtiene todos los objetos People relacionados).
fuente