我有一个相当长的查询(7个连接,现在是7个子选择,因为在原始sql 7子选择相当快 - 我甚至不知道如果我让它运行,7个连接何时完成,但是超过1分钟,相对于.05-.1秒有子选择)
当我在db上运行它时,正如我所说,执行时需要.05-.1秒。只需使用session.execute()
就可以将其减慢到一分钟以上!
我能做些什么吗?
如果您需要更多信息,请告诉我 - 我怀疑这是一个普通的sqlalchemy事情 - 就像sqlalchemy正在建立一个查询计划而不是让mysql这样做?还是...?
编辑:对两者进行解释并且它们看起来完全相同,只是sqlalchemy在extra
列中添加了“使用临时;使用filesort”。那是什么减慢了它?我该如何阻止它呢?
编辑2:绝对是sqlalchemy。我尝试使用MySQL游标执行而不是SA会话,并获得相同的.05秒运行时间。
编辑3:
创建引擎的代码:
engine_ro = create_engine(
config.ro_database_url, #string with username, password, db
pool_size=config.database_pool_size, #int
max_overflow=config.database_max_overflow, #int
pool_timeout=config.database_timeout, # int
echo=config.database_echo, #False
echo_pool=config.database_echo, #same as echo #False
listeners=[GoneAway()] if config.database_use_listeners else None)
其中GoneAway()
是执行SELECT 1
以检查连接的方法。
创建会话对象:
SessionRO = scoped_session(sessionmaker(bind=engine_ro, autocommit=False))
其中scoped_session
和sessionmaker
是sqlalchemy函数。
然后,执行查询的代码:
session = SessionRO()
results = session.execute(sql, params)
编辑4:如果有人想知道,如果我注释掉listeners
位,它仍然很慢。如果我只使用sessionmaker
而没有scoped_session。
答案 0 :(得分:4)
这是一个真正的测试套件,用于比较MySQL游标与SQLAlchemy引擎和会话。请在底部替换您的连接信息和SQL,然后运行它。让我们知道时间是什么。
import time
def time_thing(fn, description):
print "Running %s" % description
now = time.time()
try:
ret = fn()
return ret
finally:
spent = time.time() - now
print "Finished %s, took %d seconds" % (description, spent)
def with_mysqldb(sql):
import MySQLdb
conn = MySQLdb.connect(db=DBNAME, user=USERNAME, passwd=PASSWORD, host=HOST)
def go():
cursor = conn.cursor()
cursor.execute(sql)
# if result fetching is the issue:
# cursor.fetchall()
cursor.close()
time_thing(go, "Executing SQL with MySQLdb cursor")
def _sqla_engine_w_test_connection():
from sqlalchemy import create_engine
eng = create_engine(SQLALCHEMY_URL)
def test():
conn = eng.connect()
result = conn.execute("select 1")
assert result.fetchall()[0] == (1, )
time_thing(test, "Making a test connection...")
return eng
def with_sqlalchemy(sql):
eng = _sqla_engine_w_test_connection()
def go():
result = eng.execute(sql)
# if result fetching is the issue:
# result.fetchall()
result.close()
time_thing(go, "Executing SQL with SQLA engine")
def with_sqlalchemy_session(sql):
from sqlalchemy.orm import Session
eng = _sqla_engine_w_test_connection()
def go():
sess = Session(eng)
result = sess.execute(sql)
# if result fetching is the issue:
# result.fetchall()
result.close()
time_thing(go, "Executing SQL SQLA session")
SQLALCHEMY_URL = "mysql://scott:tiger@localhost/test"
DBNAME = "test"
HOST = "localhost"
USERNAME = "scott"
PASSWORD = "tiger"
SQL = "SELECT 1"
with_mysqldb(SQL)
with_sqlalchemy(SQL)
with_sqlalchemy_session(SQL)
答案 1 :(得分:4)
sqlalchemy
未设置查询计划或其他任何其他内容。它只是生成SQL并通过DB-API-2.0连接发送它。因此,如果您使用execute
生成的相同语句显式调用sqlalchemy
,它将以完全相同的方式运行。*
查看sqlalchemy
生成的查询的最简单方法是将echo=True
作为create_engine
调用的额外参数传递。
在您的情况下,sqlalchemy
生成的查询实际上与您的手动查询不同,因为它使用字符串测试整数参数,而不是使用int。
*这不是100%保证;您必须确保DB-API-2.0 connect
函数中的任何连接参数都相同,并且您和sqlalchemy
都没有执行任何PRAGMA
语句。但是你可以用与测试查询本身相同的方式测试它们。
答案 2 :(得分:1)
您使用的是哪个DBAPI?也许尝试将其改为其他东西。我现在正在使用PostgreSQL,我在pypostgresql和psycopg2之间的性能差异很大(后者更快)。
有关MySQL可用DBAPI的列表,请参阅SQLAchemy文档:第4.1.5章。
答案 3 :(得分:0)
这里的实际问题是愚蠢的。对我来说真的真的很蠢。 abarnert实际上很早就猜到了,但它太小了,我和一位同事花了两天才找到。
在控制台版本中,我正在粘贴正确的东西。 在SqlAlchemy版本中,我正在测试AN INT PARAMETER WITH A STRING。
捂脸
谢谢你的帮助,伙计们。你不喜欢这两个角色的错误吗?