带连接的相对简单的SQL查询拒绝高效

时间:2015-09-14 11:46:37

标签: mysql sql query-optimization mariadb

我在SQL中优化某个查询时遇到了一些问题(使用MariaDB),给你一些上下文:我有一个系统,可以在门票上发生“事件”(参见日志条目),但也有除了票证之外的其他一些对象(我为什么要分隔事件和ticket_event表)。我想让所有ticket_events按display_time排序。事件表现在有大约20M行。

CREATE TABLE IF NOT EXISTS `event` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `type` varchar(255) DEFAULT NULL,
  `data` text,
  `display_time` datetime DEFAULT NULL,
  `created_time` datetime DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `index_for_display_time_and_id` (`id`,`display_time`),
  KEY `index_for_display_time` (`display_time`)
) ENGINE=InnoDB  DEFAULT CHARSET=latin1;

CREATE TABLE IF NOT EXISTS `ticket_event` (
  `id` int(11) NOT NULL,
  `ticket_id` int(11) NOT NULL,
  PRIMARY KEY (`id`),
  KEY `ticket_id` (`ticket_id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
ALTER TABLE `ticket_event`
  ADD CONSTRAINT `ticket_event_ibfk_1` FOREIGN KEY (`id`) REFERENCES `event` (`id`),
  ADD CONSTRAINT `ticket_event_ibfk_2` FOREIGN KEY (`ticket_id`) REFERENCES `ticket` (`id`);

如你所见,我已经玩了一些密钥(我也为(id,ticket_id)创建了一个,因为我再次删除它,现在没有显示在这里)我执行的查询:

SELECT * FROM ticket_event
INNER JOIN event ON event.id = ticket_event.id
ORDER BY display_time DESC
LIMIT 25

该查询需要花费很长时间才能执行(如果我对特定的ticket_id进行过滤,则需要大约30秒,如果不对其进行过滤则无法可靠地完成它)。如果我对查询运行一个解释,它会显示它执行一个filesort + temporary: EXPLAIN result
我用力量指数等玩了一下,但这似乎没有解决任何问题,或者我做错了。

有谁看到我做错了什么或我能在这里优化什么?我非常不希望通过将ticket_id / host_id等添加为列来使“event”成为一个宽表,如果它们不适用则将它们设为NULL。

提前致谢!

编辑:EXPLAIN的额外图像,其中包含表格中的实际行: extra explain

4 个答案:

答案 0 :(得分:1)

您的查询会选择每行中的每一列,即使您使用LIMIT也是如此。您是否尝试按ID选择一个特定行?

答案 1 :(得分:1)

如果您尝试强制索引,那该怎么办?

SELECT * FROM ticket_event
INNER JOIN event 
FORCE INDEX (index_for_display_time) 
ON event.id = ticket_event.id
ORDER BY display_time DESC
LIMIT 25;

答案 2 :(得分:0)

KEY `index_for_display_time_and_id` (`id`,`display_time`),

没用;算了吧。它没用,因为你使用的是InnoDB,它将数据“聚集”在PK(id)上。

请将ticket_eventid更改为event_idid令人困惑,因为它感觉就像映射表的PK一样。可是等等!那没有意义?每个活动只有一张票?那为什么ticket_event存在呢?为什么不将ticket_id放入event

对于多对多表,请执行

CREATE TABLE IF NOT EXISTS `ticket_event` (
  `event_id`  int(11) NOT NULL,
  `ticket_id` int(11) NOT NULL,
  PRIMARY KEY (`event_id`, ticket_id),  -- for lookup one direction
  KEY         (`ticket_id`, event_id)   -- for the other direction
) ENGINE=InnoDB DEFAULT;

答案 3 :(得分:0)

尝试这个可能会让你获得更好的表现:

SELECT * 
FROM ticket_event 
INNER JOIN (select * from event ORDER BY display_time DESC limit 25) as b
ON b.id = ticket_event.id;