2013-05-14 38 views
2

在我看來,像經歷創建表達式樹的整個過程,然後再次創建查詢是使用sqlalchemy時的浪費時間。除了偶爾的動態查詢之外,幾乎所有的應用程序在應用程序的整個生命週期中都會完全相同(除了參數)。如何重用/克隆sqlalchemy查詢

有沒有什麼辦法可以保存一個查詢一旦創建並稍後重複使用不同的參數?或者也許有一些內部機制已經做了類似的事情?

回答

14

在我看來,經歷創建表達式樹並從中再次創建查詢的整個過程似乎是使用sqlalchemy時的浪費時間。

與其他應用程序相比,您是否有估計浪費了多少時間?在使您的程序更復雜之前,對這裏進行分析非常重要。我經常會注意到,Reddit每天的頁面瀏覽量超過10億次,他們使用SQLAlchemy Core來查詢他們的數據庫,而且最後一次查看他們的代碼時,他們沒有嘗試優化這個過程 - 他們在表達式樹上構建每一次飛行和編譯。但是,我們有用戶確定他們的具體系統實際上從這些領域的優化中受益。

我已經寫了一些背景的剖析這裏:How can I profile a SQLAlchemy powered application?

有什麼辦法,只是保存查詢,一旦它的創建和使用不同的參數以後重新使用它?或者也許有一些內部機制已經做了類似的事情?

有幾種方法,取決於您使用的API以及您想要優化的區域。

有渲染SQL兩個主要部分 - 有表達式樹的構建,可以這麼說,然後從表達式樹的字符串編譯。

樹本身,它可以是一個選擇()構建體如果使用的ORM使用Core或查詢()如果,可重複使用。 select()特別與它沒有任何關聯,可以防止它隨時被重用(insert(),delete(),update()等)。

在ORM,查詢也可以使用所述方法with_session()不同的會話中。這裏的勝利不是那麼多,因爲每次調用它時Query()仍然會產生整個select()。然而,正如我們將在下面看到的,有一個可以允許緩存的配方。

下一級優化涉及到渲染的實際SQL文本的高速緩存。這是一個需要更多關注的領域,因爲我們生成的SQL特定於目標後端;還有其他各種參數化會改變SQL本身的邊緣情況(例如在SQL Server中使用「TOP N ROWS」,我們不能在那裏使用綁定參數)。使用Connectionexecution_options()方法,這也是在其他一些地方使用提供的SQL字符串的緩存,通過發送一個詞典或其他類似字典的對象,將緩存語句的字符串格式設置compiled_cache功能,鎖定以方言,構造的身份以及發送的參數。該功能通常由ORM用於插入/更新/刪除語句。

我發佈了一個配方,它將compiled_cache功能與QueryBakedQuery相結合。通過採取任何Query,說query.bake(),你現在就可以運行該查詢與任何Session只要你不叫上更多的鏈接的方法,它應該使用SQL字符串的緩存形式,每次:

q = s.query(Foo).filter(Foo.data==bindparam('foo')).bake() 

for i in range(10): 
    result = q.from_session(s).params(foo='data 12').all() 

這是實驗性的,並不經常使用,但這正是你在這裏要求的。我建議你根據自己的需求量身定製,在使用時注意內存的使用情況,並確保遵循它的工作原理。

+1

我希望我能給予好評此一百倍。這正是我正在編寫的用於與原始代碼進行比較的查詢凍結界面。我的用例並不是應用程序的運行時,而是大量使用sqlalchemy(查詢式)界面的測試。 sqlalchemy樹操作總是出現在profiler輸出之上,但我不想在檢查是否有類似的東西之前編寫我自己的「BakedQuery」版本 - 事實證明這裏有:) – viraptor 2013-05-14 23:45:37

0

SQLAlchemy 1.0引入了baked擴展名,它是專門用於緩存對象的緩存。它緩存對象的構造和字符串編譯步驟,以最大限度地減少重複查詢中Python解釋器的開銷。

官方文檔在這裏:http://docs.sqlalchemy.org/en/latest/orm/extensions/baked.html

注意,它在緩存中不通過數據庫返回的結果集。對於這一點,你要簽出dogpile.cache

http://docs.sqlalchemy.org/en/latest/orm/examples.html#module-examples.dogpile_caching