为什么mysql分区对我的情况没有影响

时间:2016-05-19 20:05:42

标签: mysql partitioning database-partitioning

我尝试在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个req​​s:

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。

2 个答案:

答案 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)除外)。可以认为这相当于“修剪”。