@zzzeek의 훌륭한 답변입니다. 쿼리에 대한 동일한 통계에 대해 궁금한 사람들을 위해 @zzzeek 코드를 약간 수정하여 동일한 레코드를 삽입 한 후 바로 쿼리 한 다음 해당 레코드를 사전 목록으로 변환했습니다.
결과는 다음과 같습니다.
SqlAlchemy ORM: Total time for 100000 records 11.9210000038 secs
SqlAlchemy ORM query: Total time for 100000 records 2.94099998474 secs
SqlAlchemy ORM pk given: Total time for 100000 records 7.51800012589 secs
SqlAlchemy ORM pk given query: Total time for 100000 records 3.07699990273 secs
SqlAlchemy Core: Total time for 100000 records 0.431999921799 secs
SqlAlchemy Core query: Total time for 100000 records 0.389000177383 secs
sqlite3: Total time for 100000 records 0.459000110626 sec
sqlite3 query: Total time for 100000 records 0.103999853134 secs
베어 sqlite3를 사용하는 쿼리는 SQLAlchemy Core를 사용하는 것보다 여전히 약 3 배 더 빠릅니다. 베어 sqlite3 행 대신 ResultProxy가 반환 되는 데 지불하는 가격이라고 생각합니다 .
SQLAlchemy Core는 ORM을 사용하는 것보다 약 8 배 빠릅니다. 따라서 ORM을 사용하여 쿼리하는 것은 무엇이든 상관없이 훨씬 느립니다.
내가 사용한 코드는 다음과 같습니다.
import time
import sqlite3
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import Column, Integer, String, create_engine
from sqlalchemy.orm import scoped_session, sessionmaker
from sqlalchemy.sql import select
Base = declarative_base()
DBSession = scoped_session(sessionmaker())
class Customer(Base):
__tablename__ = "customer"
id = Column(Integer, primary_key=True)
name = Column(String(255))
def init_sqlalchemy(dbname = 'sqlite:///sqlalchemy.db'):
global engine
engine = create_engine(dbname, echo=False)
DBSession.remove()
DBSession.configure(bind=engine, autoflush=False, expire_on_commit=False)
Base.metadata.drop_all(engine)
Base.metadata.create_all(engine)
def test_sqlalchemy_orm(n=100000):
init_sqlalchemy()
t0 = time.time()
for i in range(n):
customer = Customer()
customer.name = 'NAME ' + str(i)
DBSession.add(customer)
if i % 1000 == 0:
DBSession.flush()
DBSession.commit()
print "SqlAlchemy ORM: Total time for " + str(n) + " records " + str(time.time() - t0) + " secs"
t0 = time.time()
q = DBSession.query(Customer)
dict = [{'id':r.id, 'name':r.name} for r in q]
print "SqlAlchemy ORM query: Total time for " + str(len(dict)) + " records " + str(time.time() - t0) + " secs"
def test_sqlalchemy_orm_pk_given(n=100000):
init_sqlalchemy()
t0 = time.time()
for i in range(n):
customer = Customer(id=i+1, name="NAME " + str(i))
DBSession.add(customer)
if i % 1000 == 0:
DBSession.flush()
DBSession.commit()
print "SqlAlchemy ORM pk given: Total time for " + str(n) + " records " + str(time.time() - t0) + " secs"
t0 = time.time()
q = DBSession.query(Customer)
dict = [{'id':r.id, 'name':r.name} for r in q]
print "SqlAlchemy ORM pk given query: Total time for " + str(len(dict)) + " records " + str(time.time() - t0) + " secs"
def test_sqlalchemy_core(n=100000):
init_sqlalchemy()
t0 = time.time()
engine.execute(
Customer.__table__.insert(),
[{"name":'NAME ' + str(i)} for i in range(n)]
)
print "SqlAlchemy Core: Total time for " + str(n) + " records " + str(time.time() - t0) + " secs"
conn = engine.connect()
t0 = time.time()
sql = select([Customer.__table__])
q = conn.execute(sql)
dict = [{'id':r[0], 'name':r[0]} for r in q]
print "SqlAlchemy Core query: Total time for " + str(len(dict)) + " records " + str(time.time() - t0) + " secs"
def init_sqlite3(dbname):
conn = sqlite3.connect(dbname)
c = conn.cursor()
c.execute("DROP TABLE IF EXISTS customer")
c.execute("CREATE TABLE customer (id INTEGER NOT NULL, name VARCHAR(255), PRIMARY KEY(id))")
conn.commit()
return conn
def test_sqlite3(n=100000, dbname = 'sqlite3.db'):
conn = init_sqlite3(dbname)
c = conn.cursor()
t0 = time.time()
for i in range(n):
row = ('NAME ' + str(i),)
c.execute("INSERT INTO customer (name) VALUES (?)", row)
conn.commit()
print "sqlite3: Total time for " + str(n) + " records " + str(time.time() - t0) + " sec"
t0 = time.time()
q = conn.execute("SELECT * FROM customer").fetchall()
dict = [{'id':r[0], 'name':r[0]} for r in q]
print "sqlite3 query: Total time for " + str(len(dict)) + " records " + str(time.time() - t0) + " secs"
if __name__ == '__main__':
test_sqlalchemy_orm(100000)
test_sqlalchemy_orm_pk_given(100000)
test_sqlalchemy_core(100000)
test_sqlite3(100000)
또한 쿼리 결과를 dicts로 변환하지 않고 테스트했으며 통계는 비슷합니다.
SqlAlchemy ORM: Total time for 100000 records 11.9189999104 secs
SqlAlchemy ORM query: Total time for 100000 records 2.78500008583 secs
SqlAlchemy ORM pk given: Total time for 100000 records 7.67199993134 secs
SqlAlchemy ORM pk given query: Total time for 100000 records 2.94000005722 secs
SqlAlchemy Core: Total time for 100000 records 0.43700003624 secs
SqlAlchemy Core query: Total time for 100000 records 0.131000041962 secs
sqlite3: Total time for 100000 records 0.500999927521 sec
sqlite3 query: Total time for 100000 records 0.0859999656677 secs
SQLAlchemy Core를 사용한 쿼리는 ORM에 비해 약 20 배 더 빠릅니다.
이러한 테스트는 매우 피상적이고 너무 심각하게 받아 들여서는 안된다는 점에 유의해야합니다. 통계를 완전히 바꿀 수있는 몇 가지 명백한 트릭이 누락되었을 수 있습니다.
성능 향상을 측정하는 가장 좋은 방법은 응용 프로그램에서 직접 수행하는 것입니다. 내 통계를 당연시하지 마십시오.