sql >> Databáze >  >> RDS >> Mysql

Proč je načítání objektů SQLAlchemy přes ORM 5-8x pomalejší než řádky přes nezpracovaný kurzor MySQLdb?

Zde je verze SQLAlchemy vašeho skriptu MySQL, která se provede za čtyři sekundy, v porovnání se třemi u 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

runtime:

total time:  0:00:04.706010

Zde je skript, který používá ORM k úplnému načtení řádků objektů; tím, že se vyhnete vytváření pevného seznamu se všemi 1 milionem objektů najednou pomocí výnosu za, proběhne to za 13 sekund s SQLAlchemy master (18 sekund s 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))

Pak můžeme rozdělit rozdíl mezi těmito dvěma přístupy a načíst pouze jednotlivé sloupce pomocí ORM:

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

Výše uvedené se znovu spustí za 4 sekundy .

Srovnání SQLAlchemy Core je výstižnější srovnání s nezpracovaným kurzorem MySQLdb. Pokud používáte ORM, ale dotazujete se na jednotlivé sloupce, jsou to v nejnovějších verzích asi čtyři sekundy.

Na úrovni ORM jsou problémy s rychlostí způsobeny tím, že vytváření objektů v Pythonu je pomalé a SQLAlchemy ORM na tyto objekty aplikuje velké množství účetnictví, když je načítá, což je nezbytné k tomu, aby splnil svou smlouvu o používání, včetně jednotky. práce, mapa identity, dychtivé načítání, sbírky atd.

Chcete-li dotaz výrazně urychlit, načtěte místo celých objektů jednotlivé sloupce. Podívejte se na techniky na adresehttp://docs .sqlalchemy.org/en/latest/faq/performance.html#result-fetching-slowness-orm které to popisují.

Pro vaše srovnání s PeeWee je PW mnohem jednodušší systém s mnohem méně funkcemi, včetně toho, že nedělá nic s mapami identity. I s PeeWee, přibližně tak jednoduchým ORM, jak je to proveditelné, to stále trvá 15 sekund , což je důkaz, že cPython je opravdu opravdu pomalý ve srovnání s nezpracovaným načítáním MySQLdb, které je v přímém C.

Pro srovnání s Javou je Java VM rychlejší než cPython . Hibernace je směšná komplikovaný, ale Java VM je extrémně rychlý díky JIT a dokonce i veškerá tato složitost nakonec běží rychleji. Pokud chcete porovnat Python s Javou, použijte Pypy.



  1. Kde najdu soubor my.ini pro Windows mysql server?

  2. mysql Počítání více výskytů multiplexovaných položek

  3. Zjistěte, zda byl řádek aktualizován nebo vložen

  4. Jak iterovat po řádku prostřednictvím dotazu mysql v php