我尝试在Mysql中测试分区的好处
我创建了两个表:一个分区,而不是。
每个表格中都有 10M 的记录。
我希望“user_to_id”列快速查询。
分区表(1024部分):
CREATE TABLE `neworder10M_part_byuser` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`site_from_id` int(11) NOT NULL,
`site_to_id` int(11) NOT NULL,
`user_from_id` int(11) NOT NULL,
`user_to_id` int(11) NOT NULL,
`created` datetime NOT NULL,
PRIMARY KEY (`id`,`user_to_id`),
KEY `composite_cover` (`user_to_id`,`user_from_id`,`site_from_id`,`site_to_id`,`created`)
) ENGINE=InnoDB
/*!50100 PARTITION BY HASH (user_to_id)
PARTITIONS 1024 */ |
带有群集密钥的表(未分区):
CREATE TABLE `neworder_10M` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`site_from_id` int(11) NOT NULL,
`site_to_id` int(11) NOT NULL,
`user_from_id` int(11) NOT NULL,
`user_to_id` int(11) NOT NULL,
`created` datetime NOT NULL,
PRIMARY KEY (`user_to_id`,`id`),
UNIQUE KEY `id_UQ` (`id`)
) ENGINE=InnoDB;
当我使用python脚本对两个表进行基准测试时,需要1000个reqs:
for i in xrange(1,REQS):
user_id = random.randint(1,10000);
cursor.execute("select * from neworder10M_part_byuser where user_to_id=%s;" % (user_id))
分区表:22 rps 未分区:22.7 rps
为什么分区表没有速度优势?因为我期望更小的数据 - 更快的查询。
并且解释还显示使用了分区:
mysql> explain select * from neworder10M_part_byuser where user_to_id=6867;
+----+-------------+-------------------------+------------+------+-----------------+-----------------+---------+-------+------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------------------------+------------+------+-----------------+-----------------+---------+-------+------+----------+-------------+
| 1 | SIMPLE | neworder10M_part_byuser | p723 | ref | composite_cover | composite_cover | 4 | const | 1009 | 100.00 | Using index |
+----+-------------+-------------------------+------------+------+-----------------+-----------------+---------+-------+------+----------+-------------+
但我没有看到现实中真正的速度有所改善......我做错了什么?
表填充代码:
def send_orders(cur,users=10000,orders=10000000):
for i in xrange(1,orders+1): //10000000 rows here
print i
from_user = random.randint(1,users)
to_user = random.randint(1,users)
from_site = random.randint(1,10000)
to_site = random.randint(1,10000)
cur.execute("INSERT INTO neworder (site_from_id, site_to_id,user_from_id, user_to_id,created) VALUES ('%d','%d','%d','%d',NOW());" % (from_user,to_user,from_site,to_site))
版本的mysql:Ver 14.14 Distrib 5.7.12,适用于Linux(x86_64)。 硬盘是ssd。
答案 0 :(得分:0)
我们不希望SELECT语句的性能有太大差异,因为查询正在使用索引范围扫描,并且因为分区表的查询正在修剪分区。
如果没有分区修剪,我们希望使用SELECT对分区表执行较慢的性能。因为那将是需要检查的1024个索引而不是一个索引。
分区提高查询性能的想法是一种谬误。
答案 1 :(得分:0)
(这既是对问题的回答,也是对一些评论的反驳。)
如果您的WHERE
子句可能导致分区修剪发生,那么它可以帮助提高复合索引的效率。因此,没有优于非分区表的优势,因为您可以选择更好的索引。
将分区修剪视为将BTree深度缩小1级。但是你必须做修剪。结果:几乎相同的成本。这是我对“未分区的10M行与一个分区中的10K行的范围扫描”问题的回答。 (@ spencer7593的答案也很好。)
我发现只有4个用例PARTITIONing
可以提高性能。有my blog。
BY RANGE
是唯一有用的分区方法。您正在使用的BY HASH
似乎完全没用。特别是,如果您对“分区键”进行范围扫描,则必须扫描所有分区 - 不能进行“修剪”。
将分区键放在任何键中通常是低效的。
UNIQUE KEY id_UQ (id)
- 为您的非分区测试制作一个普通的INDEX
;它会更有效率。处理AUTO_INCREMENT
就足够了。
(哎呀,@ spencer7593已经说了一些这些东西,并指出了我的博客。谢谢。我写的是因为我厌倦了在论坛上重复自己。)
您的特定查询(SELECT ... WHERE user_to_id = constant
)是展示无用PARTITIONing
(任何类型)的好方法。这是你真正的疑问吗?实际上,您可能还有其他一些可以从分区中受益的查询;让我们看看他们。
“小桌子上快了50倍” - 缓存?较小的表是否适合buffer_pool,但较大的表不适合? I / O是性能的最大因素。
如果WHERE user_to_id = constant
始终位于您的查询中,则将user_to_id
作为非分区表中每个索引中的第一列(INDEX(id)
除外)。可以认为这相当于“修剪”。