开发者

How can I better optimize many-to-many association queries with DataMapper?

DataMapper appears to be generating grossly sub-optimal queries for associations that use a join table. What can I do to improve the performance of these queries? Note that it generates the same queries with an implicit joi开发者_StackOverflow中文版n table, as well (:through => Resource)

Here's my setup:

class Left
  include DataMapper::Resource

  property :id, Serial

  has n, :joins
  has n, :rights, :through => :joins
end

class Join
  include DataMapper::Resource

  belongs_to :left,  :key => true
  belongs_to :right, :key => true
end

class Right
  include DataMapper::Resource

  property :id, Serial

  property :one, String
  property :two, Integer
end

Now, say I have some data populated and I want to grab all the rights associated with a left object:

Left.first.rights

DataMapper executes the following query:

SELECT rights.id, rights.one, rights.two FROM rights INNER JOIN joins ON rights.id = joins.right_idINNER JOIN lefts ON joins.left_id = lefts.idWHERE joins.left_id = 1GROUP BY rights.id, rights.one, rights.twoORDER BY rights.id

  • DataMapper is generating a completely unnecessary JOIN (first bold section). I don't trust my RDBMS (MySQL) to be smart about ignoring this. It shows up in the explain plan, as "Using index; Using temporary; Using filesort", at least.

  • What's up with the GROUP BY? It also seems completely unnecessary here - due to the composite key on the join table, I can't have duplicates. Plus, wouldn't GROUP BY rights.id have the same effect? Or even better, SELECT DISTINCT

These queries are extremely slow (on tables with more properties on both sides), and I'm not sure how to properly index the tables to support it.

It's far faster to query from the join model: Join.all(:left => Left.first).rights, though it is performing two statements:

SELECT right_id FROM joins WHERE left_id = 1
SELECT id, one, two FROM rights WHERE id = 1 ORDER BY id

Interestingly, Left.first.joins.rights goes the same route and executes the two queries above.


How about removing Join class definition, and defining Left as:

class Left
  include DataMapper::Resource

  property :id, Serial

  has n, :rights, :through => Resource
end

Believe DM, it creates good mapping for you.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜