【问题标题】:Can I get rows from SQLAlchemy that are plain arrays, rather than dictionaries?我可以从 SQLAlchemy 中获取纯数组而不是字典的行吗?
【发布时间】:2010-10-13 22:51:03
【问题描述】:

我正在尝试优化一些 Python 代码。探查器告诉我 SQLAlchemy 的 _get_col() 是杀死性能的原因。代码如下所示:

lots_of_rows = get_lots_of_rows()
for row in lots_of_rows:
    if row.x == row.y:
        print row.z

我正要检查代码,让它更像这样......

lots_of_rows = get_lots_of_rows()
for row in lots_of_rows:
    if row[0] == row[1]:
        print row[2]

...但我发现一些文档似乎表明在访问像数组这样的行对象时,您实际上仍在提取字典键。换句话说,行对象如下所示:

'x': (x object)
'0': (x object)
'y': (y object)
'1': (y object)
'z': (z object)
'2': (z object)

如果是这种情况,我怀疑我会看到按数字而不是名称访问列是否会提高性能。有没有办法让 SA 以元组列表或列表列表而不是字典列表的形式返回结果?或者,任何人都可以提出任何其他优化建议吗?

【问题讨论】:

  • SQL Alchemy 的一个主要目标是添加您想要删除的内容。也许为这个查询下拉到 mysqldb/dbapi 层是有意义的?即使没有,我还是建议您仅使用 mysqldb 驱动程序重新编写一个类似的查询,看看您能真正获得多少性能。

标签: python sqlalchemy


【解决方案1】:

请原谅显而易见的答案,但为什么您的查询中没有 row.x == row.y?例如:

mytable.select().where(mytable.c.x==mytable.c.y)

应该会给您带来巨大的性能提升。 Read the rest of the documentation.

【讨论】:

  • 我想我过于简单化的例子过于简单化了。 :) 实际的过滤器比这更复杂。
  • 那我们来看看实物吧。一般来说,如果您从数据库中获取数据,然后对其进行迭代以进行过滤,那么您可能正在做一些令人发指的事情。
  • 过滤器实际上是一个复杂的正则表达式。
  • 迈克:我可以看看吗?就您的问题而言,这是我能看到的唯一明智的答案。
  • 我同意:在客户端过滤很少是正确的答案。
【解决方案2】:

我认为row.items() 是您正在寻找的。它返回行的 (key, value) 元组列表。

Link

【讨论】:

  • 遗憾的是,items() 就是这样:返回 [(key, getattr(self, key)) for key in self.keys()] ... 并且 __getattr__() 调用 _get_col()。所以实际上这样更慢。
【解决方案3】:

SQLAlchemy 代理对底层数据库游标的所有访问,以将命名键映射到行元组中的位置并执行任何必要的类型转换。底层实现经过了相当程度的优化,几乎缓存了所有内容。查看反汇编,进一步优化的唯一方法似乎是放弃可扩展性并摆脱几个属性查找,或者诉诸动态代码生成以获得较小的收益,或者为了获得更多收益,实现相应的 ResultProxy 和 RowProxy 类C.

一些快速分析显示,在我的笔记本电脑上每次查找的开销约为 5us。如果只对数据进行微不足道的处理,那将很重要。在这种情况下,下降到 dbapi 级别可能是合理的。这并不意味着您必须失去 SQLAlchemy 的查询构建功能。只需像往常一样执行该语句并通过访问result.cursor.cursorResultProxy 获取dbapi 游标。 (result.cursor 是一个 SQLAlchemy CursorFairy 对象)然后您可以使用常规的 dbapi fetchall()、fetchone() 和 fetchmany() 方法。

但是,如果您确实在进行琐碎的处理,那么这样做可能会很有用,或者至少是数据库服务器上的过滤部分。您可能会失去数据库的可移植性,但这可能不是问题。

【讨论】:

    【解决方案4】:

    您应该发布您的分析器结果以及围绕“_get_col”调用的堆栈跟踪,以便我们知道正在调用哪个_get_col。 (以及 _get_col 是否真的是瓶颈)。

    我查看了 sqlalchemy 源代码,看起来它可能每次都调用“lookup_key”(在 engine/base.py 中),并且看起来这会在本地缓存列值,我猜是懒惰地(通过 PopulateDict)。

    您可以尝试通过直接使用 row.__props 绕过它(不推荐,因为它是私有的),也许您可​​以使用 row.cursor,但看起来您可以通过绕过 sqlalchemy(除了 sql 生成)并直接使用 w /一个光标。

    --J

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-01-24
      • 2021-11-15
      • 2020-04-09
      相关资源
      最近更新 更多