Rails 连接的慢查询

Slow Query on Rails joins

以下 rails 查询在慢速查询日志中返回:

Class ParserRun

scope :active, -> {
where(completed_at: nil)
  .joins('LEFT JOIN system_events ON parser_runs.id = system_events.parser_run_id')
  .where("system_events.created_at > '#{active_system_events_threshold}' OR parser_runs.created_at > '#{1.minute.ago.to_s(:db)}'")
}

我该如何优化它?

慢查询日志:

SELECT `parser_runs`.*
FROM `parser_runs`
INNER JOIN `system_events` ON `system_events`.`parser_run_id` = `parser_runs`.`id`
WHERE `parser_runs`.`type` IN ('DatasetParserRun')
  AND `parser_runs`.`completed_at` IS NULL
  AND (system_events.created_at <= '2017-08-05 04:03:09');

# Time: 170805  5:03:43

'show create table parser_runs;'

的输出
| parser_runs | CREATE TABLE `parser_runs` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`type` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
`customer_id` int(11) DEFAULT NULL,
`options` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
`completed_at` datetime DEFAULT NULL,
`created_at` datetime DEFAULT NULL,
`updated_at` datetime DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `index_parser_runs_on_customer_id` (`customer_id`)
) ENGINE=InnoDB AUTO_INCREMENT=143327 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci |

'show create table system_events;'

的输出
 | system_events | CREATE TABLE `system_events` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`log_level` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
`customer_id` int(11) DEFAULT NULL,
`classification` int(11) DEFAULT NULL,
`information` text COLLATE utf8_unicode_ci,
`created_at` datetime DEFAULT NULL,
`updated_at` datetime DEFAULT NULL,
`parser_run_id` int(11) DEFAULT NULL,
`notified` tinyint(1) DEFAULT '0',
`dataset_log_id` int(11) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `index_system_events_on_classification` (`classification`),
KEY `index_system_events_on_customer_id` (`customer_id`),
KEY `index_system_events_on_parser_run_id` (`parser_run_id`),
KEY `index_system_events_on_dataset_log_id` (`dataset_log_id`)
) ENGINE=InnoDB AUTO_INCREMENT=730539 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci |

EXPLAIN 的输出:

  EXPLAIN for: SELECT `parser_runs`.* FROM `parser_runs` LEFT JOIN system_events ON parser_runs.id = system_events.parser_run_id WHERE `parser_runs`.`completed_at` IS NULL AND (system_events.created_at > '2017-08-07 10:09:03')
+----+-------------+---------------+--------+-------------------------   -------------+---------+---------+--------------------------------------+-    -------+-------------+
| id | select_type | table         | type   | possible_keys                          | key     | key_len | ref                                  | rows   |    Extra       |
+----+-------------+---------------+--------+--------------------------------------+---------+---------+--------------------------------------+--------+-------------+
|  1 | SIMPLE      | system_events | ALL    | index_system_events_on_parser_run_id | NULL    | NULL    | NULL                                    | 655946 | Using where |
|  1 | SIMPLE      | parser_runs   | eq_ref | PRIMARY                                | PRIMARY | 4       | ashblood.system_events.parser_run_id |      1 | Using where |
+----+-------------+---------------+--------+--------------------------------------+---------+---------+--------------------------------------+--------+-------------+

集合中有 2 行(0.00 秒)

不要使用联接。而是将连接查询分解为单独的查询并将这些数据存储在变量中。然后从这些数据中获得您想要的结果。

查询执行计划的第一步(EXPLAIN SELECT ... 的输出)表示正在扫描整个 system_events table 以检查 [=] 中的哪些行11=] table 将在 joinparser_runs table 中使用。

请在 system_events 中的 created_at 列上添加索引并重复查询。请检查新的执行路径以验证是否正在扫描整个 table,或者是否正在使用新索引。

此外,虽然可能不是问题的根源,但您可以在 table parser_runstypecompleted_at 列上添加索引。请注意,我指的是两列(按给定顺序)的索引,而不是每列的索引。

INDEX(type, completed_at)
INDEX(completed_at, type)
INDEX(created_at, parser_run_id)
INDEX(parser_run_id, created_at)

优化器更喜欢哪些索引并不明显;添加所有这些。