Mysql InnoDb在SELECT查询上非常慢

时间:2016-11-08 10:16:30

标签: mysql performance innodb

我有一个具有以下结构的mysql表:

make runtest

并且它有超过30000000条记录。

sudo

现在的问题是它非常慢,select的结果需要很长时间才能从表中获取记录。

我的以下子查询花了将近30分钟来获取一天的记录:

mysql> show create table logs \G;

Create Table: CREATE TABLE `logs` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `request` text,
  `response` longtext,
  `msisdn` varchar(255) DEFAULT NULL,
  `username` varchar(255) DEFAULT NULL,
  `shortcode` varchar(255) DEFAULT NULL,
  `response_code` varchar(255) DEFAULT NULL,
  `response_description` text,
  `transaction_name` varchar(250) DEFAULT NULL,
  `system_owner` varchar(250) DEFAULT NULL,
  `request_date_time` datetime DEFAULT NULL,
  `response_date_time` datetime DEFAULT NULL,
  `comments` text,
  `user_type` varchar(255) DEFAULT NULL,
  `channel` varchar(20) DEFAULT 'WEB',

  /**

  other columns here....

  other 18 columns here, with Type varchar and Text

  **/

  PRIMARY KEY (`id`),
  KEY `transaction_name` (`transaction_name`) USING BTREE,
  KEY `msisdn` (`msisdn`) USING BTREE,
  KEY `username` (`username`) USING BTREE,
  KEY `request_date_time` (`request_date_time`) USING BTREE,
  KEY `system_owner` (`system_owner`) USING BTREE,
  KEY `shortcode` (`shortcode`) USING BTREE,
  KEY `response_code` (`response_code`) USING BTREE,
  KEY `channel` (`channel`) USING BTREE,
  KEY `request_date_time_2` (`request_date_time`),
  KEY `response_date_time` (`response_date_time`)
) ENGINE=InnoDB AUTO_INCREMENT=59582405 DEFAULT CHARSET=utf8

我还在表中添加了索引,但它仍然很慢。

有关如何加快速度的任何帮助?

修改 使用EXPLAIN

运行上述查询
mysql> select count(*) from logs;
+----------+
| count(*) |
+----------+
| 38962312 |
+----------+
1 row in set (1 min 17.77 sec)

1 个答案:

答案 0 :(得分:0)

目前,查询必须扫描整个表格。

但首先,让我们说一个可能的错误:

AND DATE(REQUEST_DATE_TIME) BETWEEN '2016-10-26 00:00:00'
                                AND '2016-10-27 00:00:00'

为您提供两天天的日志 - 27日的所有第26天和所有。或者那是你真正想要的吗? (BETWEEN 包含。)

但性能问题是不会使用索引,因为request_date_time隐藏在函数内(DATE)。

跳转到更好的方式来表达它:

AND REQUEST_DATE_TIME >= '2016-10-26'
AND REQUEST_DATE_TIME  < '2016-10-26' + INTERVAL 1 DAY
  • 可以将DATETIME与日期进行比较。
  • 包括26日早晨的午夜,但是27日的午夜不是。
  • 您可以轻松地将1更改为您想要的许多天 - 而无需处理闰日等。
  • 此公式允许在request_date_time上使用索引,从而严重削减要扫描的数据量。

至于其他诱人的地方:

  • !=不能很好地优化,因此没有“复合”指数可能是有益的。
  • 由于我们无法真正超越WHERE,因此没有索引对GROUP BYORDER BY有用。
  • 我对DATE()WHERE的评论不适用于GROUP BY;无需改变。

为什么有子查询?我认为它可以在一个单独的层中完成。这将消除一个相当大的临时表。 (是的,它意味着TIMESTAMPDIFF()的3次使用,但这可能比临时表便宜很多。)

多少内存? innodb_buffer_pool_size的价值是什么?

如果我的评论不够,如果您经常运行这样的查询(超过一天或超过日期范围),那么我们可以讨论构建和维护Summary table,这可能会给你一个10倍加速。