1

我试图检查实现 MySQL 数据库分区是否对我们的应用程序有益。我听说过很多关于对大量记录使用分区的好处。但令人惊讶的是,在实施分区后进行负载测试时,应用程序的响应时间减少了 3 倍。有人可以帮忙解释为什么会发生这种情况吗?

让我详细解释一下:

下面是分区“未”到位时表的 DDL。

CREATE TABLE `myTable` ( 
`column1` bigint(20) unsigned NOT NULL AUTO_INCREMENT, 
`column2` char(3) NOT NULL, 
`column3` char(3) NOT NULL, 
`column4` char(2) NOT NULL, 
`column5` smallint(4) unsigned NOT NULL, 
`column6` date NOT NULL, 
`column7` varchar(2) NOT NULL, 
`column8` tinyint(3) unsigned NOT NULL COMMENT 'Seat Count Ranges from 0-9.', 
`column9` varchar(2) NOT NULL, 
`column10` varchar(4) NOT NULL, 
`column11` char(2) NOT NULL, 
`column12` datetime NOT NULL, 
`column13` datetime DEFAULT NULL, 
PRIMARY KEY (`column1`), 
KEY `index1` (`column2`,`column3`,`column4`,`column5`,`column7`,`column6`), 
KEY `index2` (`column2`,`column3`,`column6`,`column4`) 
) ENGINE=InnoDB AUTO_INCREMENT=342024674 DEFAULT CHARSET=latin1; 

下面是基于日期字段实现“范围”分区后同一张表的 DDL。

CREATE TABLE `myTable` ( 
`column1` bigint(20) unsigned NOT NULL AUTO_INCREMENT, 
`column2` char(3) NOT NULL, 
`column3` char(3) NOT NULL, 
`column4` char(2) NOT NULL, 
`column5` smallint(4) unsigned NOT NULL, 
`column6` date NOT NULL, 
`column7` varchar(2) NOT NULL, 
`column8` tinyint(3) unsigned NOT NULL COMMENT 'Seat Count Ranges from 0-9.', 
`column9` varchar(2) NOT NULL, 
`column10` varchar(4) NOT NULL, 
`column11` char(2) NOT NULL, 
`column12` datetime NOT NULL, 
`column13` datetime DEFAULT NULL, 
PRIMARY KEY (`column1`,`column6`), 
KEY `index1` (`column2`,`column3`,`column4`,`column5`,`column7`,`column6`), 
KEY `index2` (`column2`,`column3`,`column6`,`column4`) 
) ENGINE=InnoDB AUTO_INCREMENT=342024674 DEFAULT CHARSET=latin1 
PARTITION BY RANGE COLUMNS(`column6`) 
(PARTITION date_jul_11 VALUES LESS THAN ('2011-08-01') ENGINE = InnoDB, 
PARTITION date_aug_11 VALUES LESS THAN ('2011-09-01') ENGINE = InnoDB, 
PARTITION date_sep_11 VALUES LESS THAN ('2011-10-01') ENGINE = InnoDB, 
PARTITION date_oct_11 VALUES LESS THAN ('2011-11-01') ENGINE = InnoDB, 
PARTITION date_nov_11 VALUES LESS THAN ('2011-12-01') ENGINE = InnoDB, 
PARTITION date_dec_11 VALUES LESS THAN ('2012-01-01') ENGINE = InnoDB, 
PARTITION date_jan_12 VALUES LESS THAN ('2012-02-01') ENGINE = InnoDB, 
PARTITION date_feb_12 VALUES LESS THAN ('2012-03-01') ENGINE = InnoDB, 
PARTITION date_mar_12 VALUES LESS THAN ('2012-04-01') ENGINE = InnoDB, 
PARTITION date_apr_12 VALUES LESS THAN ('2012-05-01') ENGINE = InnoDB, 
PARTITION date_may_12 VALUES LESS THAN ('2012-06-01') ENGINE = InnoDB, 
PARTITION date_jun_12 VALUES LESS THAN ('2012-07-01') ENGINE = InnoDB, 
PARTITION date_jul_12 VALUES LESS THAN ('2012-08-01') ENGINE = InnoDB, 
PARTITION date_aug_12 VALUES LESS THAN ('2012-09-01') ENGINE = InnoDB, 
PARTITION date_sep_12 VALUES LESS THAN ('2012-10-01') ENGINE = InnoDB, 
PARTITION date_oct_12 VALUES LESS THAN ('2012-11-01') ENGINE = InnoDB, 
PARTITION date_nov_12 VALUES LESS THAN ('2012-12-01') ENGINE = InnoDB, 
PARTITION date_dec_12 VALUES LESS THAN ('2013-01-01') ENGINE = InnoDB, 
PARTITION date_jan_13 VALUES LESS THAN ('2013-02-01') ENGINE = InnoDB, 
PARTITION date_feb_13 VALUES LESS THAN ('2013-03-01') ENGINE = InnoDB, 
PARTITION date_mar_13 VALUES LESS THAN ('2013-04-01') ENGINE = InnoDB, 
PARTITION date_apr_13 VALUES LESS THAN ('2013-05-01') ENGINE = InnoDB, 
PARTITION date_may_13 VALUES LESS THAN ('2013-06-01') ENGINE = InnoDB, 
PARTITION date_jun_13 VALUES LESS THAN ('2013-07-01') ENGINE = InnoDB, 
PARTITION date_oth VALUES LESS THAN (MAXVALUE) ENGINE = InnoDB); 

下面是一个示例查询,用于进行负载测试以测试性能。

SELECT column8, column9
FROM myTable
WHERE column2 = ? AND column3 = ? AND column4 =? AND column5 = ? AND column7 = ? AND column6 = ?
LIMIT 1 

?以上内容已替换为数据库中存在的真实值以进行测试。

请注意,“myTable”表中的记录数约为 3.42 亿,用于进行性能测试的测试数据数约为 200 万。

然而,正如我所说,实施分区后的性能下降了惊人的 3 倍。知道是什么原因造成的吗?

另外,如果对表结构或索引进行任何进一步的更改可能有助于解决此问题,请告诉我。

4

2 回答 2

1

请记住,分区的目标是加快查询速度,因为您的查询限制了可以在其中找到结果的分区数量。我认为问题出column6 = ?在您的测试查询中。我猜想 column6 需要一个精确的值,而不是一个范围,这会将你的结果集减少到很少的值。因此,在缩小分区的过程中,您已经基本找到了结果。并且由于索引跨多个分区进行拆分,因此缩小过程会产生成本。

您期望从 column6 上的分区中受益的那种查询是返回一系列值的查询,仅限于少数分区。例如,尝试这样的测试查询:

SELECT column8, column9
FROM myTable
WHERE column6 < ? AND column6 > ? AND column2 = ? AND column3 = ? AND column4 =? AND column5 = ?

其中 column6 范围跨越大约 2 个分区,并且总结果计数预计会相当大。

这可能会有所帮助:http ://dev.mysql.com/tech-resources/articles/partitioning.html

于 2013-02-19T06:19:11.523 回答
0

看到这里,我会考虑几件事。

第一个也是最明显的问题是,当您将数据分布在不同的设备(磁盘)上时,分区的巨大好处就出现了——而发布的代码中没有证据表明这一点。

接下来,您的分区被硬编码到特定的日期范围 - 因此当 date_oth 开始填满时,您将不得不提出一个更好的计划。

和第 6 列 = ?

所以你只测试了来自单个分区的数据的性能?充其量这不会比一张表中的所有数据快。

正如 Nathan 指出的那样,您正在按第 6 列进行分区-但您的任何索引的前面都没有这个,因此 DBMS 必须搜索每个分区中的索引以查找数据-这可能是为什么性能太差了。(我不同意分区仅有助于范围查询)。

于 2013-05-29T13:23:28.400 回答