2012-05-03 34 views
1

我使用declarative_base()並試圖找出在使用多對多關係時如何強制執行懶惰內部聯接。在sqlalchemy中強制使用多對多關係進行內部聯接

我在MySQL和InnoDB中定義了具有外鍵約束的表。

users: userid, name 
permissions: permissionid, name 
users_permissions: userid, permissionid

我正在使用metadata.reflect()來加載我的數據庫。


class User_Perm(Base): 
    __table__ = Base.metadata.tables['users_permissions'] 

class User(Base): 
    __table__ = Base.metadata.tables['users'] 

    permissions = orm.relationship('Permission', 
      secondary=User_Perm.__table__, 
      order_by='Perm.name', 
      innerjoin=True, 
      lazy=True, 
      ) 

class Permission(Base): 
    __table__ = Base.metadata.tables['permissions'] 

每當我選擇

u = Session().query(User).filter(User.name == 'myuser').first() 
u.permissions

由MySQL服務器收到的查詢是:

SELECT permissions.permissionid AS permissions_permissionid, 
    permissions.name AS permissions_name 
FROM permissions, users_permissions 
WHERE ? = users_permissions.userid 
    AND permissions.permissionid = users_permissions.permissionid 
ORDER BY permissions.name

正如我們所看到的,FROM permissions, users_permissions不是內連接。我可以強制執行此操作而不需要使用lazy=False,因爲如果我這樣做,級聯效果將會加載太多的信息,因爲permissions也與另一個表(示例中未提及)有關係,並且users也與其他表(再次,在例子中沒有提到)。我想爲所有類使用相同的模板關係。

編輯:上下文我想複製所有的SQL查詢來匹配那些從當前系統。我正嘗試從oursql遷移到sqlalchemy orm

+1

如果您需要兩個應用程序之間的字符匹配,一個使用手寫查詢,另一個使用ORM,則您會感到失望。 SQLAlchemy ORM當然可以複製結構非常相似的查詢,但是一些特性(如關係延遲加載)本質上沒有空間讓查詢充分定製。如前所述,您需要比較MySQL的EXPLAIN輸出和INNER JOIN vs.隱式連接以驗證等效性能。 – zzzeek

回答

3

MySQL is做內連接;也就是說,你顯示的查詢是內部連接的一個實現。

docs

innerjoin =假 - 如果爲true,加入渴望負荷將使用一個內連接 加入對相關的表,而不是外部聯接。該選項的目的 嚴格地是性能之一,因爲內連接 通常比外連接執行得更好。此標誌可以設置爲 當關系通過多對一使用 本地外鍵不可爲空,或者當引用是 一對一或集合保證有一個或至少 一個條目。

關鍵點是inner join vs. outer join。語法是不相關的。

注意您的查詢可以使用具有完全相同的含義inner join語法形式被轉換成一個查詢:

SELECT permissions.permissionid AS permissions_permissionid, 
    permissions.name AS permissions_name 
FROM permissions 
INNER JOIN users_permissions 
    ON permissions.permissionid = users_permissions.permissionid 
WHERE ? = users_permissions.userid 
ORDER BY permissions.name 

的MySQL通常會產生用於兩種形式相同的執行計劃。

+0

你是說在幕後,我保證MySQL會把這種類型的查詢看作是一個內部連接?我理解結果集是相同的,但並不認爲優化器將始終保證它。 – Danosaure

+1

@Danosaure我在說你的查詢**總是在邏輯上等同於使用'inner join'編寫的查詢 - 也就是說,它將返回* exact *相同的數據。另外,MySQL生成的執行計劃通常是相同的,可以用'explain'來驗證。 –

+0

@Danosaure我可能會誤解你的問題。你能澄清嗎?這些查詢在邏輯上是否相等還不夠? –

相關問題