これは、テーブル内の列の数が SQLAlchemy のパフォーマンスに劇的に影響するということですか?
これは難しい問題であり、おそらく基礎となる SQL エンジンに依存する可能性が高くなりますMySQL
。この場合、実際sqlalchemy
には、同じインターフェイスを使用しながら異なる db エンジンと対話する方法にすぎません。
SQLAlchemy は、Python SQL ツールキットおよびオブジェクト リレーショナル マッパーであり、アプリケーション開発者に SQL のフルパワーと柔軟性を提供します。
よく知られているエンタープライズ レベルの永続化パターンの完全なスイートを提供し、効率的で高性能なデータベース アクセス用に設計されており、シンプルな Python ドメイン言語に適合しています。
私は間違っているかもしれませんが、通常のを使用してベンチマークを試すことができますSQL
。
実際にいくつかのテストを実行しました...
import timeit
setup = """
from sqlalchemy import create_engine, MetaData, select, Table, Column
from sqlalchemy.dialects.sqlite import BOOLEAN, SMALLINT, VARCHAR
engine = create_engine('sqlite://', echo = False)
metadata = MetaData()
conn = engine.connect()
columns = []
for i in xrange(100):
columns.append(Column('c%d' % i, VARCHAR(1), nullable = False, server_default = '0'))
columns.append(Column('d%d' % i, VARCHAR(2), nullable = False, server_default = '00'))
user = Table('user', metadata, *columns)
user.create(engine)
conn.execute(user.insert(), [{}] * 4000)
user2 = Table('user2', metadata, Column('c0', VARCHAR(100), nullable = False, server_default = '0' * 100), \
Column('d0', VARCHAR(200), nullable = False, server_default = '0' * 200))
user2.create(engine)
conn.execute(user2.insert(), [{}] * 4000)
"""
many_columns = """
s1 = select([user]).compile(engine)
result = conn.execute(s1).fetchall()
"""
two_columns = """
s2 = select([user2]).compile(engine)
result = conn.execute(s2).fetchall()
"""
raw_many_columns = "res = conn.execute('SELECT * FROM user').fetchall()"
raw_two_columns = "res = conn.execute('SELECT * FROM user2').fetchall()"
timeit.Timer(two_columns, setup).timeit(number = 1)
timeit.Timer(raw_two_columns, setup).timeit(number = 1)
timeit.Timer(many_columns, setup).timeit(number = 1)
timeit.Timer(raw_many_columns, setup).timeit(number = 1)
>>> timeit.Timer(two_columns, setup).timeit(number = 1)
0.010751008987426758
>>> timeit.Timer(raw_two_columns, setup).timeit(number = 1)
0.0099620819091796875
>>> timeit.Timer(many_columns, setup).timeit(number = 1)
0.23563408851623535
>>> timeit.Timer(raw_many_columns, setup).timeit(number = 1)
0.21881699562072754
私はこれを見つけました:
http://www.mysqlperformanceblog.com/2009/09/28/how-number-of-columns-affects-performance/
max
彼はテストに使用しましたが、これはちょっと興味深いものでした...
私は本当に sqlalchemy が大好きなので、Python 独自の sqlite3 モジュールを使用して比較することにしました
import timeit
setup = """
import sqlite3
conn = sqlite3.connect(':memory:')
c = conn.cursor()
c.execute('CREATE TABLE user (%s)' %\
("".join(("c%i VARCHAR(1) DEFAULT '0' NOT NULL, d%i VARCHAR(2) DEFAULT '00' NOT NULL," % (index, index) for index in xrange(99))) +\
"c99 VARCHAR(1) DEFAULT '0' NOT NULL, d99 VARCHAR(2) DEFAULT '0' NOT NULL"))
c.execute("CREATE TABLE user2 (c0 VARCHAR(100) DEFAULT '%s' NOT NULL, d0 VARCHAR(200) DEFAULT '%s' NOT NULL)" % ('0'* 100, '0'*200))
conn.commit()
c.executemany('INSERT INTO user VALUES (%s)' % ('?,' * 199 + '?'), [('0',) * 200] * 4000)
c.executemany('INSERT INTO user2 VALUES (?,?)', [('0'*100, '0'*200)] * 4000)
conn.commit()
"""
many_columns = """
r = c.execute('SELECT * FROM user')
all = r.fetchall()
"""
two_columns = """
r2 = c.execute('SELECT * FROM user2')
all = r2.fetchall()
"""
timeit.Timer(many_columns, setup).timeit(number = 1)
timeit.Timer(two_columns, setup).timeit(number = 1)
>>> timeit.Timer(many_columns, setup).timeit(number = 1)
0.21009302139282227
>>> timeit.Timer(two_columns, setup).timeit(number = 1)
0.0083379745483398438
同じ結果が得られたので、データベースの実装は問題ではないと本当に思いますsqlalchemy
。
デフォルト挿入
import timeit
setup = """
from sqlalchemy import create_engine, MetaData, select, Table, Column
from sqlalchemy.dialects.sqlite import BOOLEAN, SMALLINT, VARCHAR
engine = create_engine('sqlite://', echo = False)
metadata = MetaData()
conn = engine.connect()
columns = []
for i in xrange(100):
columns.append(Column('c%d' % i, VARCHAR(1), nullable = False, server_default = '0'))
columns.append(Column('d%d' % i, VARCHAR(2), nullable = False, server_default = '00'))
user = Table('user', metadata, *columns)
user.create(engine)
user2 = Table('user2', metadata, Column('c0', VARCHAR(100), nullable = False, server_default = '0' * 100), \
Column('d0', VARCHAR(200), nullable = False, server_default = '0' * 200))
user2.create(engine)
"""
many_columns = """
conn.execute(user.insert(), [{}] * 4000)
"""
two_columns = """
conn.execute(user2.insert(), [{}] * 4000)
"""
>>> timeit.Timer(two_columns, setup).timeit(number = 1)
0.017949104309082031
>>> timeit.Timer(many_columns, setup).timeit(number = 1)
0.047809123992919922
sqlite3 モジュールでテストしています。
import timeit
setup = """
import sqlite3
conn = sqlite3.connect(':memory:')
c = conn.cursor()
c.execute('CREATE TABLE user (%s)' %\
("".join(("c%i VARCHAR(1) DEFAULT '0' NOT NULL, d%i VARCHAR(2) DEFAULT '00' NOT NULL," % (index, index) for index in xrange(99))) +\
"c99 VARCHAR(1) DEFAULT '0' NOT NULL, d99 VARCHAR(2) DEFAULT '0' NOT NULL"))
c.execute("CREATE TABLE user2 (c0 VARCHAR(100) DEFAULT '%s' NOT NULL, d0 VARCHAR(200) DEFAULT '%s' NOT NULL)" % ('0'* 100, '0'*200))
conn.commit()
"""
many_columns = """
c.executemany('INSERT INTO user VALUES (%s)' % ('?,' * 199 + '?'), [('0', '00') * 100] * 4000)
conn.commit()
"""
two_columns = """
c.executemany('INSERT INTO user2 VALUES (?,?)', [('0'*100, '0'*200)] * 4000)
conn.commit()
"""
timeit.Timer(many_columns, setup).timeit(number = 1)
timeit.Timer(two_columns, setup).timeit(number = 1)
>>> timeit.Timer(many_columns, setup).timeit(number = 1)
0.14044189453125
>>> timeit.Timer(two_columns, setup).timeit(number = 1)
0.014360189437866211
>>>