Här är SQLAlchemy-versionen av ditt MySQL-skript som fungerar på fyra sekunder, jämfört med tre för 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
körtid:
total time: 0:00:04.706010
Här är ett skript som använder ORM för att ladda objektrader helt; genom att undvika att skapa en fast lista med alla 1M objekt på en gång med yield per, körs detta på 13 sekunder med SQLAlchemy master (18 sekunder med 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))
Vi kan sedan dela skillnaden mellan dessa två tillvägagångssätt och ladda bara enskilda kolumner med ORM:
for obj in sess.query(Foo.id, Foo.a, Foo.b, Foo.c).yield_per(100).limit(1000000):
pass
Ovanstående körs igen på 4 sekunder .
Jämförelsen av SQLAlchemy Core är den mer passande jämförelsen med en rå MySQLdb-markör. Om du använder ORM men frågar efter enskilda kolumner, är det ungefär fyra sekunder i de senaste versionerna.
På ORM-nivå beror hastighetsproblemen på att det går långsamt att skapa objekt i Python, och SQLAlchemy ORM tillämpar en stor mängd bokföring på dessa objekt när den hämtar dem, vilket är nödvändigt för att det ska kunna uppfylla sitt användningskontrakt, inklusive enhet av arbete, identitetskarta, ivrig lastning, samlingar etc.
För att snabba upp frågan dramatiskt, hämta enskilda kolumner istället för hela objekt. Se teknikerna påhttp://docs .sqlalchemy.org/en/latest/faq/performance.html#result-fetching-slowness-orm som beskriver detta.
För din jämförelse med PeeWee är PW ett mycket enklare system med mycket färre funktioner, inklusive att det inte gör något med identitetskartor. Även med PeeWee, ungefär så enkel ORM som möjligt, tar det fortfarande 15 sekunder , vilket är ett bevis på att cPython verkligen är väldigt långsam jämfört med den råa MySQLdb-hämtningen som är i rak C.
För jämförelse med Java är Java VM mycket mycket snabbare än cPython . Hibernate är löjligt komplicerat, men Java VM är extremt snabb på grund av JIT och till och med all den komplexiteten går snabbare. Om du vill jämföra Python med Java, använd Pypy.