为什么 mariadb 分区没有给我更好的性能?
Why mariadb partitioning doesn't give me better performance?
问候。
先展示一下我的table方案:
CREATE TABLE `log_table` (
`rid` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`dataId` int(10) unsigned NOT NULL DEFAULT '0',
`memberId` int(10) unsigned NOT NULL DEFAULT '0',
`clientId` int(10) unsigned NOT NULL DEFAULT '0',
`qty` int(11) NOT NULL DEFAULT '0',
`timestamp` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
`typeA` tinyint(2) DEFAULT NULL,
`typeB` int(11) DEFAULT '0',
PRIMARY KEY (`rid`,`timestamp`),
KEY `idx_report1` (`timestamp`,`memberId`,`dataId`),
KEY `idx_report2` (`memberId`,`timestamp`),
KEY `idx_report3` (`dataId`,`timestamp`,`rid`),
KEY `idx_report4` (`timestamp`,`typeB`,`typeA`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
PARTITION BY RANGE (year(`timestamp`))
(PARTITION p2014 VALUES LESS THAN (2015),
PARTITION p2015 VALUES LESS THAN (2016)
);
我正在使用 MariaDB 5.5,这个 table 包含 2500 万条记录,所以我决定在 table 中创建分区以防止在不久的将来可能会出现性能问题。
您可能会看到它的时间序列、日志数据和 4 个视图。例如,其中一个视图使用以下查询:
select typeB, typeA, count(*) as number from log_table where timestamp between '2015-1-1' and '2015-2-1' group by typeB, typeA;
据我所知,此查询仅通过分区修剪从 p2015 加载数据。但是我看到原始 table 和分区版本在查询执行时间上没有太大区别。 (平均 1.94 秒对比 1.95 秒)
嗯,我认为这可能会受到每个分区中行数的影响。那么更小的分区怎么样? to_days()?
PARTITION BY RANGE (to_days(`timestamp`))
(
...
PARTITION p_2015_01 VALUES LESS THAN (to_days('2015-2-1')),
PARTITION p_2015_02 VALUES LESS THAN (to_days('2015-3-1'))
...
)
嗯,没有效果。你能告诉我我遗漏了什么吗?
编辑:对于我在查询中的错误感到抱歉。顺便说一句,EXPLAIN PARTITION 对我没有帮助。
和解释两个 table 的结果是:
// original
+------+-------------+-----------+-------+-------------------------+-------------+---------+------+---------+-----------------------------------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+------+-------------+-----------+-------+-------------------------+-------------+---------+------+---------+-----------------------------------------------------------+
| 1 | SIMPLE | org_table | range | idx_report1,idx_report4 | idx_report4 | 8 | NULL | 8828000 | Using where; Using index; Using temporary; Using filesort |
+------+-------------+-----------+-------+-------------------------+-------------+---------+------+---------+-----------------------------------------------------------+
//partition
+------+-------------+-----------+-------+-------------------------+-------------+---------+------+---------+-----------------------------------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+------+-------------+-----------+-------+-------------------------+-------------+---------+------+---------+-----------------------------------------------------------+
| 1 | SIMPLE | log_table | range | idx_report1,idx_report4 | idx_report4 | 8 | NULL | 7902646 | Using where; Using index; Using temporary; Using filesort |
+------+-------------+-----------+-------+-------------------------+-------------+---------+------+---------+-----------------------------------------------------------+
PARTITIONing
几乎没有像用户认为的那样频繁地帮助性能。
KEY `idx_report4` (`timestamp`,`typeB`,`typeA`)
不分区最适合您提供的SELECT
。 PARTITIONing
不会加快速度。
因为BETWEEN
是“包含”where timestamp between '2015-1-1' and '2015-2-1'
实际上命中了两个分区。使用 EXPLAIN PARTITIONS SELECT ...
来查看。
BY RANGE (TO_DAYS(...))
可能比 BY RANGE (YEAR(...))
好,但对于给定的查询仍然没有用。
这是我对仅 4个用例的讨论,其中PARTITIONing
有助于提高性能:http://mysql.rjweb.org/doc.php/partitionmaint
如果这种类型的查询很重要,请考虑将“汇总表”作为一种大大加快应用程序速度的方法:http://mysql.rjweb.org/doc.php/datawarehouse and http://mysql.rjweb.org/doc.php/summarytables
问候。
先展示一下我的table方案:
CREATE TABLE `log_table` (
`rid` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`dataId` int(10) unsigned NOT NULL DEFAULT '0',
`memberId` int(10) unsigned NOT NULL DEFAULT '0',
`clientId` int(10) unsigned NOT NULL DEFAULT '0',
`qty` int(11) NOT NULL DEFAULT '0',
`timestamp` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
`typeA` tinyint(2) DEFAULT NULL,
`typeB` int(11) DEFAULT '0',
PRIMARY KEY (`rid`,`timestamp`),
KEY `idx_report1` (`timestamp`,`memberId`,`dataId`),
KEY `idx_report2` (`memberId`,`timestamp`),
KEY `idx_report3` (`dataId`,`timestamp`,`rid`),
KEY `idx_report4` (`timestamp`,`typeB`,`typeA`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
PARTITION BY RANGE (year(`timestamp`))
(PARTITION p2014 VALUES LESS THAN (2015),
PARTITION p2015 VALUES LESS THAN (2016)
);
我正在使用 MariaDB 5.5,这个 table 包含 2500 万条记录,所以我决定在 table 中创建分区以防止在不久的将来可能会出现性能问题。 您可能会看到它的时间序列、日志数据和 4 个视图。例如,其中一个视图使用以下查询:
select typeB, typeA, count(*) as number from log_table where timestamp between '2015-1-1' and '2015-2-1' group by typeB, typeA;
据我所知,此查询仅通过分区修剪从 p2015 加载数据。但是我看到原始 table 和分区版本在查询执行时间上没有太大区别。 (平均 1.94 秒对比 1.95 秒)
嗯,我认为这可能会受到每个分区中行数的影响。那么更小的分区怎么样? to_days()?
PARTITION BY RANGE (to_days(`timestamp`))
(
...
PARTITION p_2015_01 VALUES LESS THAN (to_days('2015-2-1')),
PARTITION p_2015_02 VALUES LESS THAN (to_days('2015-3-1'))
...
)
嗯,没有效果。你能告诉我我遗漏了什么吗?
编辑:对于我在查询中的错误感到抱歉。顺便说一句,EXPLAIN PARTITION 对我没有帮助。
和解释两个 table 的结果是:
// original
+------+-------------+-----------+-------+-------------------------+-------------+---------+------+---------+-----------------------------------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+------+-------------+-----------+-------+-------------------------+-------------+---------+------+---------+-----------------------------------------------------------+
| 1 | SIMPLE | org_table | range | idx_report1,idx_report4 | idx_report4 | 8 | NULL | 8828000 | Using where; Using index; Using temporary; Using filesort |
+------+-------------+-----------+-------+-------------------------+-------------+---------+------+---------+-----------------------------------------------------------+
//partition
+------+-------------+-----------+-------+-------------------------+-------------+---------+------+---------+-----------------------------------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+------+-------------+-----------+-------+-------------------------+-------------+---------+------+---------+-----------------------------------------------------------+
| 1 | SIMPLE | log_table | range | idx_report1,idx_report4 | idx_report4 | 8 | NULL | 7902646 | Using where; Using index; Using temporary; Using filesort |
+------+-------------+-----------+-------+-------------------------+-------------+---------+------+---------+-----------------------------------------------------------+
PARTITIONing
几乎没有像用户认为的那样频繁地帮助性能。
KEY `idx_report4` (`timestamp`,`typeB`,`typeA`)
不分区最适合您提供的SELECT
。 PARTITIONing
不会加快速度。
因为BETWEEN
是“包含”where timestamp between '2015-1-1' and '2015-2-1'
实际上命中了两个分区。使用 EXPLAIN PARTITIONS SELECT ...
来查看。
BY RANGE (TO_DAYS(...))
可能比 BY RANGE (YEAR(...))
好,但对于给定的查询仍然没有用。
这是我对仅 4个用例的讨论,其中PARTITIONing
有助于提高性能:http://mysql.rjweb.org/doc.php/partitionmaint
如果这种类型的查询很重要,请考虑将“汇总表”作为一种大大加快应用程序速度的方法:http://mysql.rjweb.org/doc.php/datawarehouse and http://mysql.rjweb.org/doc.php/summarytables