我想分区一个非常大的表。随着业务的增长,按日期划分并不是那么好,因为每年分区越来越大。我真正喜欢的是每1000万条记录的分区。
Mysql手册显示了这个简单的例子:
CREATE TABLE employees (
id INT NOT NULL,
fname VARCHAR(30),
lname VARCHAR(30),
hired DATE NOT NULL DEFAULT '1970-01-01',
separated DATE NOT NULL DEFAULT '9999-12-31',
job_code INT NOT NULL,
store_id INT NOT NULL
)
PARTITION BY RANGE (store_id) (
PARTITION p0 VALUES LESS THAN (6),
PARTITION p1 VALUES LESS THAN (11),
PARTITION p2 VALUES LESS THAN (16),
PARTITION p3 VALUES LESS THAN MAXVALUE
);
但这意味着大于16且小于MAXVALUE的所有内容都会在最后一个分区中抛出。有没有办法在每个时间间隔(在我的情况下,1000万条记录)自动生成新分区,所以我不必继续修改活动数据库?我正在运行Mysql 5.5
谢谢!
编辑:这是我的实际表格
CREATE TABLE `my_table` (
`row_id` int(11) NOT NULL AUTO_INCREMENT,
`filename` varchar(50) DEFAULT NULL,
`timestamp` datetime DEFAULT NULL,
`unit_num` int(3) DEFAULT NULL,
`string` int(3) DEFAULT NULL,
`voltage` float(6,4) DEFAULT NULL,
`impedance` float(6,4) DEFAULT NULL,
`amb` float(6,2) DEFAULT NULL,
`ripple_v` float(8,6) DEFAULT NULL,
PRIMARY KEY (`row_id`),
UNIQUE KEY `timestamp` (`timestamp`,`filename`,`string`,`unit_num`),
KEY `index1` (`filename`),
KEY `index2` (`timestamp`),
KEY `index3` (`timestamp`,`filename`,`string`),
KEY `index4` (`filename`,`unit_num`)
) ENGINE=MyISAM AUTO_INCREMENT=690892041 DEFAULT CHARSET=latin1
并且图表的示例查询是......
SELECT DATE_FORMAT(timestamp,'%Y/%m/%d %H:%i:%s') as mytime,voltage,impedance,amb,ripple_v,unit_num
FROM my_table WHERE timestamp >= DATE_SUB('2015-07-31 00:05:59', INTERVAL 90 DAY)
AND filename = 'dlrphx10s320upsab3' and unit_num='5' and string='2'ORDER BY timestamp asc;
以下是查询的解释......
mysql> explain SELECT DATE_FORMAT(timestamp,'%Y/%m/%d %H:%i:%s') as mytime,voltage,impedance,amb,ripple_v,unit_num FROM my_table WHERE timestamp >= DATE_SUB('2015-07-31 00:05:59', INTERVAL 90 DAY) AND filename = 'dlrphx10s320upsab3' and unit_num='5' and string='2'ORDER BY timestamp asc;
+----+-------------+------------+------+-------------------------+--------+---------+-------------+-------+----------------------------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+------------+------+-------------------------+--------+---------+-------------+-------+----------------------------------------------------+
| 1 | SIMPLE | unit_tarma | ref | timestamp,index3,index4 | index4 | 58 | const,const | 13440 | Using index condition; Using where; Using filesort |
+----+-------------+------------+------+-------------------------+--------+---------+-------------+-------+----------------------------------------------------+
答案 0 :(得分:0)
首先,我必须问分区给你的好处是什么?是否有一些查询运行得更快?
没有自动分区。
相反,您应该拥有一个每天运行的作业,并计算“最后一个活动”中的行数。分区,看它是否大约10M。如果是这样,请添加另一个分区。
我建议保持"最后"分区(MAXVALUE
的分区)为空。这样你就可以REORGANIZE PARTITION
将它分成两个空分区,开销基本为零。而且我建议代替ADD PARTITION
,因为你可能会滑倒并在最后一个分区中添加一些内容。
目前还不清楚什么会引发10M。每个store_id都有多行吗?每个商店都有新的行吗?如果是这样,那么在store_id上进行分区,因为所有分区都会一直在增长。
好的,所以store_id只是参考手册中的一个例子。请提供SHOW CREATE TABLE
,以便我们可以谈论具体,而不是挥手。有太多方法可以完成这项任务。
活动是什么?
如果你大部分都打过最近的"分区,然后可以保证不均匀的分布 - 定期添加新分区并组合相邻的一对旧分区。 (我在一个系统中成功完成了这项工作。)
如果你要清洗" old"数据,然后显然您需要使用PARTITION BY RANGE(TO_DAYS(...))
并使用DROP PARTITION
加REORGANIZE PARTITION
。
还有很多其他场景。但我只知道分区提供任何性能优势的4种情况。请参阅my blog。
答案 1 :(得分:0)
(这个答案针对架构和SELECT。)
由于您预计会有数百万行,因此我首先要指出对架构的一些改进。
FLOAT(m,n)
通常是错误的'要做的事,因为它导致两个舍入。使用简单的FLOAT
(对于像电压这样的指标,似乎'正确')或使用DECIMAL(m,n)
。 FLOAT
是4个字节;在给定的情况下,DECIMAL
将是3或4个字节。
当你同时拥有INDEX(a)
和INDEX(a,b)
时,前者是不必要的,因为后者可以涵盖这种情况。你有3个不必要的KEY。这会减慢INSERTs
。
INT(3)
- 您是说#3; 3位数字"?如果是这样,请考虑TINYINT UNSIGNED
(值0..255)为1个字节而不是INT
为4个字节。这将节省许多MB的磁盘空间,因此速度快。 (另请参阅SMALLINT
等,SIGNED
或UNSIGNED
。)
如果重复filename
,您可能希望"规范化"它。这样可以节省很多MB。
除非您需要NOT NULL
,否则请使用NULL
。
AUTO_INCREMENT=690892041
意味着你大约有1/3的灾难发生在id
,最高可达20亿。你用id
做什么了吗?摆脱专栏将避免这个问题;并将UNIQUE KEY
更改为PRIMARY KEY
。 (如果确实需要id
,请进一步讨论。)
ENGINE=MyISAM
- 转换有一些有利和不利的后果。该表将变为2-3倍。正确的'选择PRIMARY KEY
会显着加快此 SELECT
的速度。 (并且可能会或可能不会减慢其他SELECTs
。)
关于SELECT
的说明:由于string
和unit_num
是查询中的常量,因此ORDER BY timestamp asc, string asc, unit_num asc
的最后两个字段是不必要的。如果它们与SELECT
中不明显的原因相关,那么我的建议可能不完整。
此
WHERE filename = 'foobar'
AND unit_num='40'
AND string='2'
AND timestamp >= ...
由INDEX(filename, unit_name, string, timestamp)
优化处理。除了 timestamp
需要最后之外,列的顺序并不重要。重新排列当前的UNIQUE
键,可以为您提供最佳索引。 (同时,没有一个索引对这个SELECT
非常有用。)使它成为PRIMARY KEY
和表InnoDB会使它更快。
分区?没有优势。不是为了表现;不是你提到的任何其他事情。分区的一个常见用途是清除“旧”。如果您打算这样做,请进一步讨论。
在巨大的牌桌中,最好同时查看所有重要的SELECTs
,这样我们就不会在摧毁其他人的速度的同时加快速度。 可能甚至可以证明分区有助于这种权衡。