【问题标题】:Execute sql query with Elixir使用 Elixir 执行 sql 查询
【发布时间】:2010-12-24 22:57:01
【问题描述】:

我在一个连接到 postgres 数据库的项目中使用 Elixir。我想在我连接到的数据库上运行以下查询,但我不知道该怎么做,因为我对 Elixir 和 SQLAlchemy 还很陌生。有人知道怎么做吗?

VACUUM FULL ANALYZE table

更新

错误是:“UnboundExecutionError:找不到在 SQL 表达式或此会话上配置的绑定”。与之前发出的 session.close() 的结果相同。我确实尝试过 metadata.bind.execute() 并且适用于简单的选择。但是对于 VACUUM 它说 - “InternalError: (InternalError) VACUUM 不能在事务块内运行”,所以现在我想弄清楚如何关闭它。

更新 2

我可以执行查询,但我仍然遇到相同的错误 - 即使我创建了一个新会话并关闭了前一个会话。

from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker

# ... insert stuff
old_session.commit()
old_session.close()

new_sess = sessionmaker(autocommit=True)
new_sess.configure(bind=create_engine('postgres://user:pw@host/db', echo=True))
sess = new_sess()
sess.execute('VACUUM FULL ANALYZE table')
sess.close()

我得到的输出是

2009-12-10 10:00:16,769 INFO sqlalchemy.engine.base.Engine.0x...05ac VACUUM FULL ANALYZE table
2009-12-10 10:00:16,770 INFO sqlalchemy.engine.base.Engine.0x...05ac {}
2009-12-10 10:00:16,770 INFO sqlalchemy.engine.base.Engine.0x...05ac ROLLBACK
finishing failed run, (InternalError) VACUUM cannot run inside a transaction block
 'VACUUM FULL ANALYZE table' {}

更新 3

感谢所有回复的人。 我找不到我想要的解决方案,但我想我会选择这里描述的PostgreSQL - how to run VACUUM from code outside transaction block?。这并不理想,但它有效。

【问题讨论】:

    标签: python postgresql sqlalchemy python-elixir


    【解决方案1】:

    如果您有权访问 SQLAlchemy 会话,则可以通过其execute 方法执行任意 SQL 语句:

    session.execute("VACUUM FULL ANALYZE table")
    

    【讨论】:

    • 我试过了,但我得到了 UnboundExecutionError。 session 是 sqlalchemy.orm.scoping.ScopedSession 的一个实例,当我为我的其他查询调用 session.commit() 时,它可以工作。提交之前还是之后有关系吗?
    • 您可以在执行语句之前尝试执行 session.close()。此外,该错误希望与回溯一起出现,这说明了什么?
    • “UnboundExecutionError: 找不到在 SQL 表达式或此会话上配置的绑定”。与之前发出的 session.close() 的结果相同。我确实尝试过 metadata.bind.execute() 并且适用于简单的选择。但是对于 VACUUM 它说 - “InternalError: (InternalError) VACUUM 不能在事务块内运行”,所以现在我想弄清楚如何关闭它。
    【解决方案2】:

    (取决于 Postgres 版本)您很可能 do not want 运行“VACUUM FULL”。

    【讨论】:

      【解决方案3】:

      UnboundExecutionError 表示您的会话未绑定到引擎,并且无法从传递给execute() 的查询中发现引擎。您可以直接使用engine.execute(),也可以将额外的mapper 参数(映射器或与查询中使用的表对应的映射模型)传递给session.execute(),以帮助SQLAlchemy 发现合适的引擎。

      InternalError 表示您正在尝试在显式(使用 BEGIN 语句)启动的事务中执行此语句。您是否在没有致电commit() 的情况下发表了一些声明?如果是这样,只需在执行 VACUUM 之前调用 commit()rollback() 方法关闭事务。另请注意,sessionmaker() 有几个参数告诉 SQLAlchemy 何时应该开始事务。

      【讨论】:

      • 啊,谢谢。我确实尝试过(请参阅更新 2),但它似乎仍在某处开始交易。我想也许它只是在重用旧连接,但是 echo_pool=True 输出表明正在建立一个新连接。
      【解决方案4】:

      您需要将会话绑定到引擎

      session.bind = metadata.bind
      session.execute('YOUR SQL STATEMENT')
      

      【讨论】:

        【解决方案5】:

        该死。我知道答案就在我的眼皮底下。假设您像我一样设置连接。

        metadata.bind = 'postgres://user:pw@host/db'
        

        解决方法很简单

        conn = metadata.bind.engine.connect()
        
        old_lvl = conn.connection.isolation_level
        conn.connection.set_isolation_level(0)
        conn.execute('vacuum analyze table')
        conn.connection.set_isolation_level(old_lvl)
        

        这类似于PostgreSQL - how to run VACUUM from code outside transaction block? 此处的建议 因为在这一切之下,sqlalchemy 使用 psycopg 建立与 postgres 的连接。 Connection.connection 是 psycopg 连接的代理。一旦我意识到这一点,这个问题又回到了我的脑海中,我决定再试一次。

        希望这对某人有所帮助。

        【讨论】: