我有这个ActiveRecord查询
issue = Issue.find(id)
issue.articles.includes(:category).merge(Category.where(permalink: perma))
并将其翻译成mysql查询
SELECT `articles`.`id` AS t0_r0, `articles`.`title` AS t0_r1,
`articles`.`hypertitle` AS t0_r2, `articles`.`html` AS t0_r3,
`articles`.`author` AS t0_r4, `articles`.`published` AS t0_r5,
`articles`.`category_id` AS t0_r6, `articles`.`issue_id` AS t0_r7,
`articles`.`date` AS t0_r8, `articles`.`created_at` AS t0_r9,
`articles`.`updated_at` AS t0_r10, `articles`.`photo_file_name` AS t0_r11,
`articles`.`photo_content_type` AS t0_r12, `articles`.`photo_file_size` AS t0_r13,
`articles`.`photo_updated_at` AS t0_r14, `categories`.`id` AS t1_r0,
`categories`.`name` AS t1_r1, `categories`.`permalink` AS t1_r2,
`categories`.`created_at` AS t1_r3, `categories`.`updated_at` AS t1_r4,
`categories`.`issued` AS t1_r5, `categories`.`order_articles` AS t1_r6
FROM `articles` LEFT OUTER JOIN `categories` ON
`categories`.`id` = `articles`.`category_id` WHERE
`articles`.`issue_id` = 409 AND `categories`.`permalink` = 'Διεθνή' LIMIT 1
在这个查询的解释中,我看到使用了错误的索引
+----+-------------+------------+-------+---------------------------------------------------------------------------+-------------------------------+---------+-------+------+----------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+------------+-------+---------------------------------------------------------------------------+-------------------------------+---------+-------+------+----------+-------------+
| 1 | SIMPLE | categories | const | PRIMARY,index_categories_on_permalink | index_categories_on_permalink | 768 | const | 1 | 100.00 | |
| 1 | SIMPLE | articles | ref | index_articles_on_issue_id_and_category_id, index_articles_on_category_id | index_articles_on_category_id | 2 | const | 10 | 100.05 | Using where |
+----+-------------+------------+-------+---------------------------------------------------------------------------+-------------------------------+---------+-------+------+----------+-------------+
我有两个索引,category_id
单独和issue_id - category_id
。
在此查询中,我使用issue_id
和category_id
进行搜索,使用index_articles_on_issue_id_and_category_id
时比index_articles_on_category_id
要快得多。
如何使用有效记录查询选择正确的索引?
答案 0 :(得分:30)
你可以像这样使用索引来促进:
class Issue
def self.use_index(index)
# update: OP fixed my mistake
from("#{self.table_name} USE INDEX(#{index})")
end
end
# then
Issue.use_index("bla").where(some_condition: true)
答案 1 :(得分:1)
use_index
添加到ActiveRecord::Relation
。将some discussion添加到Rails核心已有多年,但是,看起来PR和分支都被放弃了。
如果您知道所使用的数据库及其局限性,则可以轻松地将其添加到自己的代码库中以便使用。
与@krichard的解决方案非常相似,不同之处在于它更通用化了所有使用的模型,而不仅仅是Issue
。
config/initializers/active_record_relation.rb
class ActiveRecord::Relation
# Allow passing index hints to MySQL in case the query planner gets confused.
#
# Example:
# Message.first.events.use_index( :index_events_on_eventable_type_and_eventable_id )
# #=> Event Load (0.5ms) SELECT `events`.* FROM `events` USE INDEX (index_events_on_eventable_type_and_eventable_id) WHERE `events`.`eventable_id` = 123 AND `events`.`eventable_type` = 'Message'
#
# MySQL documentation:
# https://dev.mysql.com/doc/refman/5.7/en/index-hints.html
#
# See https://github.com/rails/rails/pull/30514
#
def use_index( index_name )
self.from( "#{ self.quoted_table_name } USE INDEX ( #{ index_name } )" )
end
end
这将允许您使用类似的内容:
issue.articles.includes( :category ).use_index( :index_articles_on_issue_id_and_category_id )
生成的SQL将包括:
FROM articles USE INDEX( index_articles_on_issue_id_and_category_id )