在超大表上选择MySQL数据库性能

时间:2018-09-08 07:56:39

标签: mysql indexing innodb

我有一个销售数据表,每天平均插入1,329,415行。我必须每天从表中以不同格式生成报告。但是从表中查询太慢了。这是我的SHOW CREATE TABLE命令的输出。

CREATE TABLE `query_manager_table` (
  `mtime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `region_id` int(2) NOT NULL,
  `rtslug` varchar(10) DEFAULT NULL,
  `dsid` int(3) NOT NULL,
  `dpid` int(3) NOT NULL,
  `route_number` int(4) NOT NULL,
  `route_id` int(11) NOT NULL,
  `rtlid` int(11) NOT NULL,
  `retailer_code` varchar(16) DEFAULT NULL,
  `platform_code` varchar(16) DEFAULT NULL,
  `prid` int(4) NOT NULL,
  `skid` int(4) NOT NULL,
  `group` int(4) NOT NULL,
  `family` int(4) NOT NULL,
  `volume` float DEFAULT NULL,
  `value` float(7,2) DEFAULT NULL,
  `date` date NOT NULL DEFAULT '0000-00-00',
  `outlets` int(4) NOT NULL,
  `visited` int(4) NOT NULL,
  `channel` int(3) DEFAULT NULL,
  `subchannel` int(3) DEFAULT NULL,
  `tpg` int(4) DEFAULT NULL,
  `ioq` int(10) DEFAULT NULL,
  `sales_time` int(11) DEFAULT NULL,
  PRIMARY KEY (`dpid`,`route_id`,`rtlid`,`prid`,`skid`,`date`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1

/*!50100 PARTITION BY LIST (YEAR(date) * 100 + QUARTER(date))
(PARTITION y2017q1 VALUES IN (201701) ENGINE = InnoDB,
 PARTITION y2017q2 VALUES IN (201702) ENGINE = InnoDB,
 PARTITION y2017q3 VALUES IN (201703) ENGINE = InnoDB,
 PARTITION y2017q4 VALUES IN (201704) ENGINE = InnoDB,
 PARTITION y2018q1 VALUES IN (201801) ENGINE = InnoDB,
 PARTITION y2018q2 VALUES IN (201802) ENGINE = InnoDB,
 PARTITION y2018q3 VALUES IN (201803) ENGINE = InnoDB,
 PARTITION y2018q4 VALUES IN (201804) ENGINE = InnoDB,
 PARTITION y2019q1 VALUES IN (201901) ENGINE = InnoDB,
 PARTITION y2019q2 VALUES IN (201902) ENGINE = InnoDB,
 PARTITION y2019q3 VALUES IN (201903) ENGINE = InnoDB,
 PARTITION y2019q4 VALUES IN (201904) ENGINE = InnoDB) */

现在,我只想通过查询以下信息来了解9月1日至9月9日零售商的销售情况-

SELECT
            query_manager_table.dpid,
            query_manager_table.route_id,
            query_manager_table.rtlid,
            query_manager_table.prid,
            SUM(query_manager_table.`volume`) AS sales,
            1 AS memos
        FROM
            query_manager_table
        WHERE
            query_manager_table.date BETWEEN '2018-09-01'
        AND '2018-09-08'    
GROUP BY
            query_manager_table.dpid,
            query_manager_table.rtlid,
            query_manager_table.date

但是大约需要500-700秒。我已经添加了dpid IN (1,2,.....)prid IN (1,2,....),因为两个文件都被添加为主键。然后300秒后输出。我做错了什么?

+----+-------------+---------------------+------+---------------+------+---------+------+-----------+----------------------------------------------+
| id | select_type | table               | type | possible_keys | key  | key_len | ref  | rows      | Extra                                        |
+----+-------------+---------------------+------+---------------+------+---------+------+-----------+----------------------------------------------+
|  1 | SIMPLE      | query_manager_table | ALL  | PRIMARY       | NULL | NULL    | NULL | 129065467 | Using where; Using temporary; Using filesort |
+----+-------------+---------------------+------+---------------+------+---------+------+-----------+----------------------------------------------+

当我在条件中添加所有dpid和prid时,EXPAIN看起来像

+----+-------------+---------------------+-------+---------------+---------+---------+------+--------+----------------------------------------------+
    | id | select_type | table               | type  | possible_keys | key     | key_len | ref  | rows   | Extra                                        |
    +----+-------------+---------------------+-------+---------------+---------+---------+------+--------+----------------------------------------------+
    |  1 | SIMPLE      | query_manager_table | range | PRIMARY       | PRIMARY | 4       | NULL | 128002 | Using where; Using temporary; Using filesort |
    +----+-------------+---------------------+-------+---------------+---------+---------+------+--------+----------------------------------------------+

有什么方法可以优化表或查询? 如果我为第一个运行EXPLAIN PARTITIONS SELECT ...,则得到-

+----+-------------+---------------------+-------------------------------------------------------------------------------------------------+------+---------------+------+---------+------+-----------+----------------------------------------------+
| id | select_type | table               | partitions                                                                                      | type | possible_keys | key  | key_len | ref  | rows      | Extra                                        |
+----+-------------+---------------------+-------------------------------------------------------------------------------------------------+------+---------------+------+---------+------+-----------+----------------------------------------------+
|  1 | SIMPLE      | query_manager_table | y2017q1,y2017q2,y2017q3,y2017q4,y2018q1,y2018q2,y2018q3,y2018q4,y2019q1,y2019q2,y2019q3,y2019q4 | ALL  | PRIMARY       | NULL | NULL    | NULL | 127129410 | Using where; Using temporary; Using filesort |
+----+-------------+---------------------+-------------------------------------------------------------------------------------------------+------+---------------+------+---------+------+-----------+----------------------------------------------+

第二个我得到-

+----+-------------+---------------------+-------------------------------------------------------------------------------------------------+-------+---------------+---------+---------+------+--------+----------------------------------------------+
| id | select_type | table               | partitions                                                                                      | type  | possible_keys | key     | key_len | ref  | rows   | Extra                                        |
+----+-------------+---------------------+-------------------------------------------------------------------------------------------------+-------+---------------+---------+---------+------+--------+----------------------------------------------+
|  1 | SIMPLE      | query_manager_table | y2017q1,y2017q2,y2017q3,y2017q4,y2018q1,y2018q2,y2018q3,y2018q4,y2019q1,y2019q2,y2019q3,y2019q4 | range | PRIMARY       | PRIMARY | 4       | NULL | 153424 | Using where; Using temporary; Using filesort |
+----+-------------+---------------------+-------------------------------------------------------------------------------------------------+-------+---------------+---------+---------+------+--------+----------------------------------------------+

2 个答案:

答案 0 :(得分:1)

INDEXes用于提高SELECTs中的效率。

根据定义,一个PRIMARY KEY(在MySQL中)是唯一的INDEX。它应该具有最少的一组唯一标识一行的列。

任何唯一索引(包括PK)也是一个“唯一性约束”,这可以防止插入多个具有相同set(如果有值)的行。

索引从“左起”使用。也就是说,对于INDEX(a,b),如果a没用,它将不会进入b

PARTITION BY LIST实际上是没有用的。即使有,也很少会提高性能。您向我们展示了一些查询;让我们看看更多的典型查询,以便我们可以帮助您进行索引和分区。

    WHERE
        query_manager_table.date BETWEEN '2018-09-01'
                                     AND '2018-09-08'    

乞求INDEX(date)。在复合索引中,不会到达“范围”之后的列。也就是说,在INDEX(date, x, y)中,对date进行一定范围的测试(例如WHERE中的8天),将不允许它使用x或{{ 1}}。另一方面,y 使用更多索引。

WHERE date = '2018-09-01' AND x=1-请勿在{{1​​}}或float(7,2)上使用(m,n)选项。而是切换到FLOAT

DOUBLE始终为4个字节。请参见DECIMAL(1个字节),INT(2个字节)等。仅此一项,就可以将表的大小减半。

对此进行解释:

TINYINT

管理对伪距SMALLINT使用第一个(记住:'leftmost'),但是由于下一个PRIMARY KEY (`dpid`,`route_id`, ... WHERE ... AND dpid IN (...) AND ... ,因此不能在PK中使用其他任何内容。

这说明了为什么第二个IN具有较小的“行”。另外,请注意“ key_len”中的“ 4”,即route_id中的字节数。

在进行了一些更改之后,请回来,以便我们可以讨论使用摘要表来加快处理速度。但是,“修改”可能会导致此优化的复杂性。

您有多少RAM? EXPLAIN的值是什么?

除非必须使用,否则请不要使用GUID。由于随机性,它们会使大型表上的动作变慢。

答案 1 :(得分:0)

我不会结合实际的数据字段来构成主键。我将只有一个字段,并使用一个自动递增的整数或该值的GUID。必须经过六个字段来标识唯一记录比经过一个要花费更多的时间,并且正如您所说的,如果用户输入关键数据,则存在重复字段的风险。

如果出于商业原因要使这六个字段在一起时唯一,则还应制定例程以识别插入的记录是否与这些字段重复。如果您要批量插入,则需要在插入记录后执行此操作,而不是在插入记录时对其进行检查。您还需要对这六个字段建立索引,以加快查询重复项的速度。

对于您的SELECT查询,您可能希望为WHERE子句中的字段建立索引。无论如何,您都需要阅读执行计划并尝试使用不同的索引和键结构(可能更容易对数据的一部分进行操作)。 Google提供了“ mysql执行计划”,以获取大量信息。