【问题标题】:How to partition this large MySQL table?如何对这个大的 MySQL 表进行分区?
【发布时间】:2014-06-18 01:09:26
【问题描述】:

我有一个大约有 10 亿行的表,如下所示:

CREATE TABLE `ghcnddata` (
`date`  date NOT NULL ,
`TMIN`  float(6,2) NULL DEFAULT NULL ,
`TMAX`  float(6,2) NULL DEFAULT NULL ,
`PRCP`  float(6,2) NULL DEFAULT NULL ,
`SNOW`  float(6,2) NULL DEFAULT NULL ,
`SNWD`  float(6,2) NULL DEFAULT NULL ,
`station`  varchar(30),
PRIMARY KEY (`station`, `date`),
INDEX `date` (`date`) USING BTREE ,
INDEX `station` (`station`) USING BTREE 
) ENGINE=InnoDB

我运行的所有查询都有如下所示的一行:

 WHERE `station` = "ABSUXNNSDIA3"

还有如下一行:

 AND `date` BETWEEN "1990-01-01" AND "2010-01-01"

station 字段大约有 30,000 个唯一值,并且没有查询涉及超过 1 个站点。理想情况下,我想模拟拥有 33,333 个不同的表;每个站点一个(10 亿/30,000 = 33,333)。

最初我认为我可以通过在station 上设置HASH index 来完成此操作,但显然这仅适用于MEMORY 表。然后我以为我PARTITION BY KEY (station) PARTITIONS 33333,但似乎分区太多了。

在这种情况下我应该怎么做?我无法真正进行实验,因为表格太大,任何修改都需要很长时间。

没有主/从、复制、集群或类似的东西。

【问题讨论】:

  • 您确定分区是个好主意吗?
  • 好吧,不——但如果这不是分区的好情况,那是什么?该表上的查询需要很长时间,但如果我将 33333 站之一复制到它自己的表中,并查询它 - 它很快。如果不实际制作 33333 个表,就没有办法模拟吗?
  • 一张表速度快的原因不能扩展到这么多表 - 与单张表相比,您将只有 1/33333 的键和池缓存。
  • 将 PK 反转为 (date, station) 将极大地帮助索引位置,然后您可能需要删除日期索引才能真正使用它。
  • 我明白了。好的,我试试看。

标签: mysql sql database-partitioning large-data


【解决方案1】:

每个工作站不一定需要一个分区。 HASH 或 KEY 分区的要点是你定义了固定数量的分区,多个值被映射到那个分区中。

mysql> alter table ghcnddata partition by key(station) partitions 31;

出于习惯,我为分区数量选择了一个素数,因为如果数据遵循某种模式(比如只有奇数值),它有助于在分区上更均匀地分配数据。

mysql> insert into ghcnddata (station, date) values ('abc', now());
mysql> insert into ghcnddata (station, date) values ('def', now());
mysql> insert into ghcnddata (station, date) values ('ghi', now());
mysql> insert into ghcnddata (station, date) values ('jkl', now());
mysql> insert into ghcnddata (station, date) values ('mno', now());
mysql> insert into ghcnddata (station, date) values ('qrs', now());
mysql> insert into ghcnddata (station, date) values ('tuv', now());
mysql> insert into ghcnddata (station, date) values ('wxyz', now());

当我使用EXPLAIN PARTITIONS 运行查询时,它会告诉我它必须读取哪个分区。

mysql> explain partitions select * from ghcnddata where station='tuv';
+----+-------------+-----------+------------+------+-----------------+---------+---------+-------+------+-------------+
| id | select_type | table     | partitions | type | possible_keys   | key     | key_len | ref   | rows | Extra       |
+----+-------------+-----------+------------+------+-----------------+---------+---------+-------+------+-------------+
|  1 | SIMPLE      | ghcnddata | p21        | ref  | PRIMARY,station | PRIMARY | 122     | const |    1 | Using where |
+----+-------------+-----------+------------+------+-----------------+---------+---------+-------+------+-------------+

我们可以看到,在这种情况下,当我参考站 'tuv' 时,只读取了分区 21。

请注意,分区并不是万能的。如果您在定义为分区键的同一列中搜索常量值(不是变量或连接条件等),它只会有助于减少查询的工作量。

我刚刚插入的行应该是大致均匀分布的,而不是完美均匀分布的。并且不能保证每个分区有一个 station 值。

mysql> select table_name, partition_name, table_rows 
    from information_schema.partitions where table_name='ghcnddata';

+------------+----------------+------------+
| table_name | partition_name | table_rows |
+------------+----------------+------------+
| ghcnddata  | p0             |          1 |
| ghcnddata  | p1             |          2 |
| ghcnddata  | p2             |          0 |
| ghcnddata  | p3             |          0 |
| ghcnddata  | p4             |          0 |
| ghcnddata  | p5             |          0 |
| ghcnddata  | p6             |          0 |
| ghcnddata  | p7             |          0 |
| ghcnddata  | p8             |          0 |
| ghcnddata  | p9             |          0 |
| ghcnddata  | p10            |          0 |
| ghcnddata  | p11            |          0 |
| ghcnddata  | p12            |          0 |
| ghcnddata  | p13            |          0 |
| ghcnddata  | p14            |          0 |
| ghcnddata  | p15            |          0 |
| ghcnddata  | p16            |          0 |
| ghcnddata  | p17            |          0 |
| ghcnddata  | p18            |          0 |
| ghcnddata  | p19            |          0 |
| ghcnddata  | p20            |          0 |
| ghcnddata  | p21            |          2 |
| ghcnddata  | p22            |          1 |
| ghcnddata  | p23            |          1 |
| ghcnddata  | p24            |          1 |
| ghcnddata  | p25            |          0 |
| ghcnddata  | p26            |          0 |
| ghcnddata  | p27            |          0 |
| ghcnddata  | p28            |          0 |
| ghcnddata  | p29            |          0 |
| ghcnddata  | p30            |          0 |
+------------+----------------+------------+

P.S.:station 上的表索引是多余的,因为那已经是主键的最左侧列了。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-08-25
    • 1970-01-01
    • 1970-01-01
    • 2011-06-27
    • 1970-01-01
    • 1970-01-01
    • 2013-06-25
    相关资源
    最近更新 更多