我有一个大约有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)。
最初我认为我可以通过在HASH index
上设置station
来完成此操作,但显然这只适用于MEMORY
个表。然后我想我PARTITION BY KEY (station) PARTITIONS 33333
,但似乎分区太多了。
在这种情况下我该怎么办?我无法真正进行实验,因为表格太大,任何修改都需要很长时间。
没有主/从或复制或群集或任何类似的东西。
答案 0 :(得分:0)
每个电台不一定需要一个分区。 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。
请注意,分区不是灵丹妙药。如果在定义为分区键的同一列中搜索常量值(不是变量或连接条件等),它只会减少查询的工作量。< / p>
我刚刚插入的行应该大致均匀分布,但完全均匀分布。并且不保证每个分区的值为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
上的表格索引是多余的,因为它已经是主键最左边的列。