如何使用DataMapper更好地优化多对多关联查询?

时间:2011-04-27 18:37:41

标签: ruby datamapper

DataMapper似乎为使用连接表的关联生成了非常次优的查询。我该怎么做才能提高这些查询的性能?请注意,它也使用隐式连接表生成相同的查询(:through => Resource

这是我的设置:

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

现在,假设我填充了一些数据,并且我想获取与左对象相关的所有权利:

Left.first.rights

DataMapper执行以下查询:

SELECT rights.id, rights.one, rights.two FROM rights INNER JOIN joins ON rights.id = joins.right_id INNER JOIN lefts ON joins.left_id = lefts.id WHERE joins.left_id = 1 GROUP BY rights.id, rights.one, rights.two ORDER BY rights.id

  • DataMapper正在生成一个完全不必要的JOIN(第一个粗体部分)。我不相信我的RDBMS(MySQL)能够聪明地忽略这一点。它在解释计划中显示为“使用索引;使用临时;使用filesort”,至少。

  • GROUP BY有什么用?这里似乎完全没必要 - 由于连接表上的复合键,我不能有重复项。另外,GROUP BY rights.id不会有同样的效果吗?甚至更好,SELECT DISTINCT

这些查询非常慢(在双方都有更多属性的表上),我不确定如何正确索引表以支持它。

从连接模型查询速度要快得多:Join.all(:left => Left.first).rights,尽管它执行两个语句:

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

有趣的是,Left.first.joins.rights采用相同的路线并执行上述两个查询。

1 个答案:

答案 0 :(得分:3)

如何删除Join类定义,并将Left定义为:

class Left
  include DataMapper::Resource

  property :id, Serial

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

相信DM,它为您创建了良好的映射。