Mysql
 sql >> база данни >  >> RDS >> Mysql

Защо зареждането на SQLAlchemy обекти през ORM е 5-8 пъти по-бавно от редовете чрез необработен MySQLdb курсор?

Ето версията на SQLAlchemy на вашия MySQL скрипт, която се изпълнява за четири секунди, в сравнение с три за MySQLdb:

from sqlalchemy import Integer, Column, create_engine, MetaData, Table
import datetime

metadata = MetaData()

foo = Table(
    'foo', metadata,
    Column('id', Integer, primary_key=True),
    Column('a', Integer(), nullable=False),
    Column('b', Integer(), nullable=False),
    Column('c', Integer(), nullable=False),
)


class Foo(object):
    def __init__(self, a, b, c):
        self.a = a
        self.b = b
        self.c = c

engine = create_engine('mysql+mysqldb://scott:[email protected]/test', echo=True)
start = datetime.datetime.now()

with engine.connect() as conn:
    foos = [
        Foo(row['a'], row['b'], row['c'])
        for row in
        conn.execute(foo.select().limit(1000000)).fetchall()
    ]


print "total time: ", datetime.datetime.now() - start

време на изпълнение:

total time:  0:00:04.706010

Ето скрипт, който използва ORM за пълно зареждане на редовете на обекта; като се избягва създаването на фиксиран списък с всички 1M обекти наведнъж, като се използва yield per, това се изпълнява за 13 секунди с SQLAlchemy master (18 секунди с rel 0.9):

import time
from sqlalchemy import Integer, Column, create_engine, Table
from sqlalchemy.orm import Session
from sqlalchemy.ext.declarative import declarative_base

Base = declarative_base()


class Foo(Base):
    __table__ = Table(
        'foo', Base.metadata,
        Column('id', Integer, primary_key=True),
        Column('a', Integer(), nullable=False),
        Column('b', Integer(), nullable=False),
        Column('c', Integer(), nullable=False),
    )


engine = create_engine('mysql+mysqldb://scott:[email protected]/test', echo=True)

sess = Session(engine)

now = time.time()

# avoid using all() so that we don't have the overhead of building
# a large list of full objects in memory
for obj in sess.query(Foo).yield_per(100).limit(1000000):
    pass

print("Total time: %d" % (time.time() - now))

След това можем да разделим разликата между тези два подхода и да заредим само отделни колони с ORM:

for obj in sess.query(Foo.id, Foo.a, Foo.b, Foo.c).yield_per(100).limit(1000000):
    pass

Горното отново се изпълнява след 4 секунди .

Сравнението на SQLAlchemy Core е по-подходящото сравнение с необработен MySQLdb курсор. Ако използвате ORM, но правите заявка за отделни колони, това е около четири секунди в най-новите версии.

На ниво ORM проблемите със скоростта са, защото създаването на обекти в Python е бавно и SQLAlchemy ORM прилага голямо количество счетоводство към тези обекти, докато ги извлича, което е необходимо, за да изпълни договора си за използване, включително единица на работа, карта на самоличността, нетърпеливо зареждане, колекции и т.н.

За да ускорите драстично заявката, извличайте отделни колони вместо пълни обекти. Вижте техниките на http://docs .sqlalchemy.org/en/latest/faq/performance.html#result-fetching-slowness-orm които описват това.

За сравнение с PeeWee, PW е много по-проста система с много по-малко функции, включително че не прави нищо с карти за самоличност. Дори и с PeeWee, приблизително толкова прост ORM, колкото е възможно, пак отнема 15 секунди , което е доказателство, че cPython е наистина много бавен в сравнение със суровото извличане на MySQLdb, което е в прав C.

За сравнение с Java, Java VM е много по-бърза от cPython . Хибернацията есмешно сложно, но Java VM е изключително бърза поради JIT и дори цялата тази сложност работи по-бързо. Ако искате да сравните Python с Java, използвайте Pypy.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Как да генерирам данни в MySQL?

  2. MySql разлика между две времеви марки в дни?

  3. Съобщение за грешка в синтаксиса на MySQL Операнд трябва да съдържа 1 колона(и)

  4. Как използвате командата източник на MySQL за импортиране на големи файлове в Windows

  5. Как да направите изместването на ограничението динамично, като използвате само (My)SQL