我有一个约6M行的表,每个查询提取大约20,000-30,000行,并进行索引优化。然而,由于很多人连续提取这些行(每30秒左右),该网站通常会为人们超时。
我最近将数据库迁移到具有大量RAM(每台服务器512GB)的3服务器MySQL集群,性能没有太大提升。
我想知道分区是否是提高绩效的最佳方式。由于我完全没有分手经验,我想我会在这里问。
我的问题是,所有这些行都有一个值为0,1,2或3的列。
是否有可能以某种方式将值为1的所有行放在一个分区的某个列中,而将另一个列中的值为2的所有行放在一个列中?它们会根据主表中更新的值自动移动吗?最重要的是,它可以帮助提高性能,因为它只需要通过在20,000-30,000而不是6,000,000中找到1行
答案 0 :(得分:1)
是的,MySQL支持分区。您可以很好地定义分区,例如:
CREATE TABLE MyTable (
id INT AUTO_INCREMENT PRIMARY KEY,
somestuff INT,
otherstuff VARCHAR(100),
KEY (somestuff)
) PARTITION BY HASH(id) PARTITIONS 4;
INSERT INTO MyTable () VALUES (), (), (), ();
您可以在此之后验证每个分区中的行数:
SELECT PARTITION_NAME, TABLE_ROWS FROM INFORMATION_SCHEMA.PARTITIONS WHERE TABLE_NAME='MyTable';
+----------------+------------+
| PARTITION_NAME | TABLE_ROWS |
+----------------+------------+
| p0 | 1 |
| p1 | 1 |
| p2 | 1 |
| p3 | 1 |
+----------------+------------+
然而,当他们尝试在MySQL中使用分区时,有两件事会引起人们的注意:
首先,正如https://dev.mysql.com/doc/refman/5.7/en/partitioning-limitations-partitioning-keys-unique-keys.html所说:
表中的每个唯一键必须使用表格分区表达式中的每一列。
这意味着如果您想在上面的示例中按somestuff
进行分区,则无法进行。这将要求主键包含分区表达式中命名的列。
ALTER TABLE MyTable PARTITION BY HASH(somestuff) PARTITIONS 4;
ERROR 1503 (HY000): A PRIMARY KEY must include all columns in the table's partitioning function
您可以通过从表中删除任何主键或唯一键约束来解决此问题,但这会使您遇到格式错误的表格。
其次,只有在您可以利用partition pruning时,分区才会加快查询速度,并且仅当您的查询条件包含分区表达式中使用的列时才会发生这种情况。
mysql> EXPLAIN PARTITIONS SELECT * FROM MyTable WHERE SomeStuff = 3;
+----+-------------+---------+-------------+------+---------------+-----------+---------+-------+------+-------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+---------+-------------+------+---------------+-----------+---------+-------+------+-------+
| 1 | SIMPLE | MyTable | p0,p1,p2,p3 | ref | somestuff | somestuff | 5 | const | 4 | NULL |
+----+-------------+---------+-------------+------+---------------+-----------+---------+-------+------+-------+
注意这说它需要扫描分区p0,p1,p2,p3--即整个表。没有分区修剪,因此没有性能提升,因为它没有减少检查的行数。
如果您在分区表达式中使用的列中搜索特定值,您可以看到MySQL能够减少它扫描的分区数量:
mysql> EXPLAIN PARTITIONS SELECT * FROM MyTable WHERE id = 3;
+----+-------------+---------+------------+-------+---------------+---------+---------+-------+------+-------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+---------+------------+-------+---------------+---------+---------+-------+------+-------+
| 1 | SIMPLE | MyTable | p3 | const | PRIMARY | PRIMARY | 4 | const | 1 | NULL |
+----+-------------+---------+------------+-------+---------------+---------+---------+-------+------+-------+
在非常具体的情况下,分区可以提供很多帮助,但分区并不像大多数人想象的那样多样化。
在大多数情况下,最好在表中定义更具体的索引,以支持您需要运行的查询。