超大表上的MySQL数据库性能选择
我有一个销售数据表,其中平均每天插入1329415行。我必须每天从表格中以不同的格式生成报告。但是表中的查询太慢了。这是我的SHOW CREATE TABLE命令输出超大表上的MySQL数据库性能选择,mysql,indexing,innodb,Mysql,Indexing,Innodb,我有一个销售数据表,其中平均每天插入1329415行。我必须每天从表格中以不同的格式生成报告。但是表中的查询太慢了。这是我的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, `ds
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秒。我在1,2中添加了dpid,。。。。。并在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 |
+----+-------------+---------------------+------+---------------+------+---------+------+-----------+----------------------------------------------+
当我在where条件中添加所有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 |
+----+-------------+---------------------+-------+---------------+---------+---------+------+--------+----------------------------------------------+
有没有办法优化表或查询?
如果我运行解释分区,请选择。。。对于第一个,然后获得-
+----+-------------+---------------------+-------------------------------------------------------------------------------------------------+------+---------------+------+---------+------+-----------+----------------------------------------------+
| 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 |
+----+-------------+---------------------+-------------------------------------------------------------------------------------------------+-------+---------------+---------+---------+------+--------+----------------------------------------------+
我不会将实际数据字段组合成主键。我将使用一个字段,并使用一个自动递增的整数,或者可能是一个GUID作为值。必须通过六个字段来识别唯一的记录比通过一个字段要花费更多的时间,并且正如您所说的,如果用户输入关键数据,您将面临重复字段的风险 如果您有业务原因使这六个字段在一起时是唯一的,那么您还应该制定一个例程,以确定插入的记录是否与这些字段的现有记录重复。如果要批量插入,则需要在插入记录后执行此操作,而不是在插入记录时检查每个记录。您还需要为这六个字段编制索引,以加快重复项的查询速度 对于SELECT查询,您可能需要为WHERE子句中的字段编制索引。在任何情况下,您都需要阅读执行计划,并尝试使用不同的索引和键结构,这在数据子集上可能更容易实现。Google mysql执行计划提供大量信息。索引用于提高选择的效率 根据定义,MySQL中的一个主键是唯一索引。它应该具有唯一标识行的最小列集 包括PK的任何唯一索引也是唯一性约束-这防止插入具有相同set if值的多行 索引从左边开始使用。也就是说,对于INDEXa,b,如果a没有用处,它就不会到达b 按列表分区实际上是无用的。它很少(如果有的话)提高性能。您向我们展示了几个问题;让我们看更多的典型查询,这样我们可以帮助您进行索引和分区
WHERE
query_manager_table.date BETWEEN '2018-09-01'
AND '2018-09-08'
乞求独立。在复合索引中,不会到达“range”后面的列。也就是说,在INDEXdate,x,y中,测试日期的范围,例如WHERE中的8天,不允许它使用x或y。另一方面,其中date='2018-09-01'和x=1将使用更多的索引
float7,2-不要在FLOAT或DOUBLE上使用m,n选项。相反,切换到十进制
INT总是4个字节。请参阅TINYINT 1字节、SMALLINT 2字节等。仅此一项就可以将表大小减半
要解释这一点:
PRIMARY KEY (`dpid`,`route_id`, ...
WHERE ... AND dpid IN (...) AND ...
设法在中为伪范围使用第一个memory:“leftmost”,但不能在PK中使用任何其他内容,因为route_id是下一个
这就解释了为什么第二个解释的行数更小。另外,请注意key_len中的4,这是dpid中的字节数
在您做了一些更改之后,请回来,这样我们就可以讨论使用汇总表来加快速度。但是,修改可能会导致此优化的复杂性
你有多少公羊?innodb\u buffer\u pool\u size的值是多少
除非必须,否则不要使用guid;由于随机性,它们会减慢大型表上的操作。我认为您已经将自己与主键和索引混淆了。您应该将dpid、rtlid和date索引为这三者的复合索引,而不是将它们添加到主索引中key@MadhurBhaiya,主键本身不是索引吗?是的。但这并不意味着您将每个字段都定义为PK。主键基本上是指数据库中的一个主引用唯一字段。@MadhurBhaiya,根据我的项目场景,我的主键是正确的。我实际搜索日期范围的最长时间。dpid很少使用。我应该分别添加日期和dpid作为键吗?当你说你的PK根据你的项目场景是正确的时,你的确切意思是什么?我同意@MadhurBhaiya;密钥结构中的字段似乎多于唯一标识每条记录所需的字段。请问,您所说的这个项目场景是什么?非常感谢您真正解释的答案。我的服务器RAM是64GB,innodb_buffer_pool_大小是21474836480。大多数情况下,我需要日期范围之间的数据。那你有什么建议?我会使用自动递增PK并将现有PK设置为UK吗?是否也将每列的单个索引设为当前主键?我的表大小超过100GB,并且每天都在增加。MySQL的哪个版本?请公关
ovide解释分区选择。。。对于两个查询。问题已编辑。请看一看。我的MySQL版本:5.6。40@MdRiadHossain-注意所有分区是如何列出的,从而表明没有分区修剪,从而支持我的论点,即按列表划分是没有好处的。