最近需要分析业务代码中MySQL语句执行效率,对于直接显示执行SQL语句的地方,可以直接将SQL语句和参数拼接后的结果打印出来,但是对于用SQLAlchemy Query查询的地方,就需要想办法打印出最后实际执行的语句。找了下各种方案,最后结果如下:
方式一:
SQLAlchemy支持在创建数据库引擎时,通过echo=true,将连接这个数据库引擎的所有执行语句打印出来:
engine = create_engine("<db_rul>", echo=True)
这种方式会自动将连接数据库过程中的所有类型语句,以及这些语句的参数列表打印出来。也即是说,这种方式打印出的语句和语句中的参数是分离的。
方式二:
query = session.query(Model).filter(*query_cond).order_by(order_info)
对于某一个像上边这样的查询或插入语句,可以直接通过下边的方式,打印出不包含参数的SQL语句
print str(query)
这种方式得到的SQL也不可直接执行,因为对应的参数变量没有被替换
方式三
from sqlalchemy.dialects import mysql
print str(query.statement.compile(dialect=mysql.dialect(), compile_kwargs={"literal_binds": True}))
这种方式可以打印包含参数的执行语句,但是参数只包括数字和字符串等基本类型。其中dialects表示需要的数据库方言,我这里用的mysql。
基于方式三,增加部分代码,来打印datetime等类型的参数。
from sqlalchemy.orm import Query
from datetime import date, timedelta
def render_query(statement, dialect=None):
query = session.query(Model).filter(*query_cond)
print render_query(query)
result = query.all()
"""
if isinstance(statement, Query):
if dialect is None:
dialect = statement.session.bind.dialect
statement = statement.statement
elif dialect is None:
dialect = statement.bind.dialect
class LiteralCompiler(dialect.statement_compiler):
def visit_bindparam(self, bindparam, within_columns_clause=False,
literal_binds=False, **kwargs):
return self.render_literal_value(bindparam.value, bindparam.type)
def render_array_value(self, val, item_type):
if isinstance(val, list):
return "{%s}" % ",".join([self.render_array_value(x, item_type) for x in val])
return self.render_literal_value(val, item_type)
def render_literal_value(self, value, type_):
if isinstance(value, long):
return str(value)
elif isinstance(value, (basestring, date, datetime.datetime, timedelta)):
return "'%s'" % str(value).replace("'", "''")
elif isinstance(value, list):
return "'{%s}'" % (",".join([self.render_array_value(x, type_.item_type) for x in value]))
return super(LiteralCompiler, self).render_literal_value(value, type_)
return LiteralCompiler(dialect, statement).process(statement)
上边的代码支持 SQA 1.0.13及以上版本,支持select、insert和update命令。对其他版本的情况,可以参考
参考:
http://stackoverflow.com/questions/5631078/sqlalchemy-print-the-actual-query