python SQLAlchemy散列连接

nhn9ugyo  于 2023-03-11  发布在  Python
关注(0)|答案(2)|浏览(130)

我有一个查询,我想在上面连接一个子查询,使用outerjoin函数调用可以很好地工作,问题是发出的查询运行在2- 3秒内,而在SQL Server控制台中显式指定连接方法为LEFT HASH JOIN时几乎可以立即运行。
是否有一种方法可以强制SQLAlchemy发出LEFT HASH JOIN语句沿着其代码如下

query = query.outerjoin(sub_query, join_conditions, method='hash')

?我尝试在StackOverflow和互联网上的其他地方进行搜索,但没有找到任何相关的内容。如果Microsoft SQL Server对结果有任何影响,我将使用它。
如果是为了简化ORM的使用而牺牲性能的情况,那么我很乐意做出这种权衡,但显然我不希望这样做!

00jrzges

00jrzges1#

在进一步阅读之后,正如Ilija在他们的评论中提到的,这在SQLAlchemy中是不可能的。
然而,同一篇阅读还指出,在SQL查询上指定连接提示通常应该只是查询优化计划的最后一步-例如here
我并没有试图将我所追求的功能修补到SQLAlchemy中,而是回过头来重新检查了我在问题中缩写的join_conditions的内容,发现通过调整连接逻辑,我可以让SQL Server生成更快的执行计划。

hfyxw5xn

hfyxw5xn2#

您可以在Dialect中更新SQLCompiler以支持必要的功能,如下所示。
我怀疑这对于大多数实际用例来说是否是一个合理的解决方案,但我相信它确实具有一些教育价值。

from sqlalchemy.dialects.sqlite import base

class MySQLiteCompiler(base.SQLiteCompiler):
  # Update the visit_join method to support a hypothetical
  # MAGIC keyword.
  #
  # For that we copy the code over from
  # https://github.com/sqlalchemy/sqlalchemy/blob/e7aabd54c4defe237cecfa80863f0d7fa5a48035/lib/sqlalchemy/sql/compiler.py#L4987
  # and add a small modification (marked below).
  #
  # The borrowed piece of code is subject to:
  # Copyright (C) 2005-2023 the SQLAlchemy authors and contributors.
  # Released under the MIT license.
  def visit_join(self, join, asfrom=False, from_linter=None, **kwargs):
    if from_linter:
        from_linter.edges.update(
            itertools.product(
                join.left._from_objects, join.right._from_objects
            )
        )
    if join.full:
        join_type = " FULL OUTER JOIN "
    elif join.isouter:
        join_type = " LEFT OUTER JOIN "
        # --- Start of modification ---
        if join.ismagic:
          join_type = " LEFT MAGIC JOIN "
        # --- End of modification ---
    else:
        join_type = " JOIN "
    return (
        join.left._compiler_dispatch(
            self, asfrom=True, from_linter=from_linter, **kwargs
        )
        + join_type
        + join.right._compiler_dispatch(
            self, asfrom=True, from_linter=from_linter, **kwargs
        )
        + " ON "
        # TODO: likely need asfrom=True here?
        + join.onclause._compiler_dispatch(
            self, from_linter=from_linter, **kwargs
        )
    )

class MyDialect(base.SQLiteDialect):
    statement_compiler = MySQLiteCompiler

示例用法:

import sqlalchemy as sa

my_join = sa.join(sa.select("a"), sa.select("b"),
                  sa.text("whatever"), isouter=True)
my_join.ismagic = True 

print(my_join.compile(dialect=MyDialect()))

相关问题