假设您有两个模型,User和City,由第三个模型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.users
,city.city_permissions
,user.cities
,user.city_permissions
表现同样出色?
答案 0 :(得分:4)
对我来说很好。
生成的连接应该只在实体表的PK ID上,或者在连接表中的FK ID上 - 这两个都是索引。
查看生成的ActiveRecord SQL并将其与索引进行比较可能会很好。
根据您所在的数据库,您可以通过Explain计划运行该SQL(或者存在任何工具,我在想Oracle)
为简化您的代码,您还可以查看使用has_and_belongs_to_many
。这样你就可以摆脱CityPermission对象了(除非你想用它来存储数据)
答案 1 :(得分:1)
以下是ActiveRecord为user.cities
生成的SQL:
SELECT `cities`.* FROM `cities` INNER JOIN city_permissions ON (cities.id = city_permissions.city_id) 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_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为user.city_permissions
生成的SQL:
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手册:
对于前面表格中的每个行组合,从此表中读取一行。除了system和const类型之外,这是最好的连接类型。当连接使用索引的所有部分并且索引是PRIMARY KEY或UNIQUE索引时使用它。
对于前面表格中的每个行组合,将从此表中读取所有具有匹配索引值的行。如果连接仅使用键的最左前缀或者键不是PRIMARY KEY或UNIQUE索引(换句话说,如果连接不能基于键值选择单行),则使用ref。如果使用的密钥只匹配几行,这是一个很好的连接类型。