SQLAlchemyで少し遅く実行されていたクエリをセットアップして、それを最適化しようとしました。結果は、未知の理由で、暗黙のクロス結合を使用します。これは、大幅に遅くなり、間違った結果をもたらすことになります。私はテーブル名と引数を匿名化しましたが、そうでなければ変更はありませんでした。誰がこれがどこから来ているか知っていますか?SQLAlchemyは何の理由もなくクロス結合を出す
見つけやすくするために:新しいものと古いものとの差異は、新しいものが長いSELECTを持ち、どのジョインよりも前にWHEREの3つのテーブルすべてを記述していることです。
オリジナルコード:flask_sqlalchemy.get_debug_queriesによって記録されたよう
cust_name = u'Bob'
proj_name = u'job1'
item_color = u'blue'
query = (db.session.query(Item.name)
.join(Project, Customer)
.filter(Customer.name == cust_name,
Project.name == proj_name)
.distinct(Item.name))
# some conditionals determining last filter, resolving to this one:
query = query.filter(Item.color == item_color)
result = query.all()
オリジナル放出されたSQL:
QUERY: SELECT DISTINCT ON (items.name) items.name AS items_name
FROM items JOIN projects ON projects.id = items._project_id JOIN customers ON customers.id = projects._customer_id
WHERE customers.name = %(name_1)s AND projects.name = %(name_2)s AND items.color = %(color_1)s
Parameters: `{'name_2': u'job1', 'state_1': u'blue', 'name_1': u'Bob'}
新コード:flask_sqlalchemy.get_debug_queriesによって記録されたよう
cust_name = u'Bob'
proj_name = u'job1'
item_color = u'blue'
query = (db.session.query(Item)
.options(Load(Item).load_only('name', 'color'),
joinedload(Item.project, innerjoin=True).load_only('name').
joinedload(Project.customer, innerjoin=True).load_only('name'))
.filter(Customer.name == cust_name,
Project.name == proj_name)
.distinct(Item.name))
# some conditionals determining last filter, resolving to this one:
query = query.filter(Item.color == item_color)
result = query.all()
新放出されるSQL :
QUERY: SELECT DISTINCT ON (items.nygc_id) items.id AS items_id, items.name AS items_name, items.color AS items_color, items._project_id AS items__project_id, customers_1.id AS customers_1_id, customers_1.name AS customers_1_name, projects_1.id AS projects_1_id, projects_1.name AS projects_1_name
FROM customers, projects, items JOIN projects AS projects_1 ON projects_1.id = items._project_id JOIN customers AS customers_1 ON customers_1.id = projects_1._customer_id
WHERE customers.name = %(name_1)s AND projects.name = %(name_2)s AND items.color = %(color_1)s
Parameters: `{'state_1': u'blue', 'name_2': u'job1', 'name_1': u'Bob'}
重要な場合は、基礎となるデータベースがPostgreSQLです。
クエリの元の目的はItem.name
である必要があります。最適化の試みは、私が考えているよりも実際には役に立たないように見えますが、joinedload
、load_only
などを追加すると実際に役立つ場合に備えて、そのクロス結合がどこから来たのかを知りたいと思っています。
それはうまくいきました。たとえ速度が意味的に違っていても、何が起こっているかを知ることは良いことです。 –