8

假设您有两个模型,用户和城市,由第三个模型 CityPermission 连接:

class CityPermission < ActiveRecord::Base
  belongs_to :city
  belongs_to :user
end

class City < ActiveRecord::Base
  has_many :city_permissions
  has_many :users, :through => :city_permissions
end

class User < ActiveRecord::Base
  has_many :city_permissions
  has_many :cities, :through => :city_permissions
end

目前,我使用以下迁移代码片段创建连接表和表的索引:

create_table :city_permissions do |t|
      t.integer :user_id, :city_id
      t.other_fields ...
end

add_index(:city_permissions, :user_id)
add_index(:city_permissions, :city_id)

这些是要创建的最佳索引吗?这些索引是否允许通过连接表来回快速访问,以及在表本身内快速查找,还是有其他更好的方法?以不同的方式重申这一点,这些索引,给定city并且user是类 City 和 User 的实例变量,是否允许city.userscity.city_permissionsuser.citiesuser.city_permissions都表现得同样好?

4

2 回答 2

4

对我来说看上去很好。

生成的连接应该只是在实体表的 PK ID 上,或者在连接表中的 FK ID 上——它们都是索引。

查看生成的 ActiveRecord SQL 并将其与索引进行比较可能会很好。

然后,根据您使用的数据库,您可以通过解释计划运行该 SQL(或任何存在的工具,我在这里认为是 Oracle)

为了简化您的代码,您也可以考虑使用has_and_belongs_to_many。这会让你摆脱 CityPermission 对象(除非你想用它来存储数据本身)

于 2008-10-21T22:40:47.747 回答
1

这是 ActiveRecord 生成的 SQL user.cities

SELECT `cities`.* FROM `cities` INNER JOIN city_permissions ON (cities.id = city_permissions.city_id) WHERE (city_permissions.user_id = 1 )

在下面解释结果:

+----+-------------+------------------+--------+---------------------------------------------------------------------+-----------------------------------+---------+-------------------------------------------------+------+-------------+
| id | select_type | table            | type   | possible_keys                                                       | key                               | key_len | ref                                             | rows | Extra       |
+----+-------------+------------------+--------+---------------------------------------------------------------------+-----------------------------------+---------+-------------------------------------------------+------+-------------+
|  1 | SIMPLE      | city_permissions | ref    | index_city_permissions_on_user_id,index_city_permissions_on_city_id | index_city_permissions_on_user_id | 5       | const                                           |    1 | Using where |
|  1 | SIMPLE      | cities           | eq_ref | PRIMARY                                                             | PRIMARY                           | 4       | barhopolis_development.city_permissions.city_id |    1 |             |
+----+-------------+------------------+--------+---------------------------------------------------------------------+-----------------------------------+---------+-------------------------------------------------+------+-------------+

这是 ActiveRecord 生成的 SQL user.city_permissions

SELECT * FROM `city_permissions` WHERE (`city_permissions`.user_id = 1)

使用该查询的 EXPLAIN 结果:

+----+-------------+------------------+------+-----------------------------------+-----------------------------------+---------+-------+------+-------------+
| id | select_type | table            | type | possible_keys                     | key                               | key_len | ref   | rows | Extra       |
+----+-------------+------------------+------+-----------------------------------+-----------------------------------+---------+-------+------+-------------+
|  1 | SIMPLE      | city_permissions | ref  | index_city_permissions_on_user_id | index_city_permissions_on_user_id | 5       | const |    1 | Using where |
+----+-------------+------------------+------+-----------------------------------+-----------------------------------+---------+-------+------+-------------+

看起来它确实工作正常。来自 MySQL 手册:

eq_ref

对于先前表中的每个行组合,从该表中读取一行。除了 system 和 const 类型之外,这是最好的连接类型。当连接使用索引的所有部分并且索引是 PRIMARY KEY 或 UNIQUE 索引时使用它。

参考

对于先前表中的每个行组合,从该表中读取具有匹配索引值的所有行。如果连接仅使用键的最左侧前缀,或者如果键不是 PRIMARY KEY 或 UNIQUE 索引(换句话说,如果连接不能基于键值选择单行),则使用 ref。如果使用的键只匹配几行,这是一个很好的连接类型。

于 2008-10-21T22:42:35.450 回答