创建 20,000 个表是个坏主意。不久之后,您将需要 40,000 张桌子,甚至更多。
我在我的书SQL Antipatterns中将这种综合症称为Metadata Tribbles。每次您计划创建“每个 X 的表”或“每个 X 的列”时,您都会看到这种情况。
当您拥有数以万计的表时,这确实会导致真正的性能问题。每个表都需要 MySQL 维护内部数据结构、文件描述符、数据字典等。
还有实际的操作后果。您真的要创建一个系统,每次新用户注册时都需要您创建一个新表吗?
相反,我建议您使用MySQL Partitioning。
这是对表进行分区的示例:
CREATE TABLE statistics (
id INT AUTO_INCREMENT NOT NULL,
user_id INT NOT NULL,
PRIMARY KEY (id, user_id)
) PARTITION BY HASH(user_id) PARTITIONS 101;
这为您提供了定义一个逻辑表的好处,同时还将表划分为许多物理表,以便在查询分区键的特定值时更快地访问。
例如,当您像示例一样运行查询时,MySQL 仅访问包含特定 user_id 的正确分区:
mysql> EXPLAIN PARTITIONS SELECT * FROM statistics WHERE user_id = 1\G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: statistics
partitions: p1 <--- this shows it touches only one partition
type: index
possible_keys: NULL
key: PRIMARY
key_len: 8
ref: NULL
rows: 2
Extra: Using where; Using index
分区的 HASH 方法意味着将行按整数分区键的模数放置在分区中。这确实意味着许多 user_id 映射到同一个分区,但每个分区平均只有 1/N 的行数(其中 N 是分区数)。并且您使用恒定数量的分区定义表,因此您不必每次获得新用户时都对其进行扩展。
您可以选择最多 1024 个(或 MySQL 5.6 中为 8192 个)的任意数量的分区,但有些人报告说当分区数达到这么高时会出现性能问题。
建议使用质数分区。如果您的 user_id 值遵循某种模式(例如仅使用偶数),则使用质数分区有助于更均匀地分布数据。
重新评论您的问题:
我如何确定合理数量的分区?
对于 HASH 分区,如果你使用 101 个分区,就像我在上面的例子中展示的那样,那么任何给定的分区平均大约有 1% 的行。你说你的统计表有 3000 万行,所以如果你使用这个分区,每个分区只有 300k 行。这对 MySQL 来说更容易阅读。您也可以(并且应该)使用索引——每个分区都有自己的索引,它只有整个未分区表上的索引的 1%。
那么如何确定合理的分区数量的答案是:你的整个表有多大,你希望分区平均有多大?
分区的数量不应该随着时间的推移而增长吗?如果是这样:我怎样才能自动化呢?
如果您使用 HASH 分区,则不一定需要增加分区数。最终你可能总共有 300 亿行,但我发现当你的数据量增长几个数量级时,无论如何都需要一个新的架构。如果您的数据增长到那么大,您可能需要在多个服务器上进行分片以及分区到多个表中。
也就是说,您可以使用 ALTER TABLE 重新分区表:
ALTER TABLE statistics PARTITION BY HASH(user_id) PARTITIONS 401;
这必须重组表(就像大多数 ALTER TABLE 更改一样),所以预计需要一段时间。
您可能想要监控分区中数据和索引的大小:
SELECT table_schema, table_name, table_rows, data_length, index_length
FROM INFORMATION_SCHEMA.PARTITIONS
WHERE partition_method IS NOT NULL;
与任何表一样,您希望活动索引的总大小适合您的缓冲池,因为如果 MySQL 在 SELECT 查询期间必须将部分索引交换进出缓冲池,则性能会受到影响。
如果您使用 RANGE 或 LIST 分区,则添加、删除、合并和拆分分区更为常见。请参阅http://dev.mysql.com/doc/refman/5.6/en/partitioning-management-range-list.html
我鼓励您阅读有关分区的手册部分,并查看这个不错的演示文稿:使用 MySQL 5.1 分区提高性能。