为什么MySQL不使用我的分区作为索引?

为什么MySQL不使用我的分区作为索引?,mysql,sql,database-partitioning,Mysql,Sql,Database Partitioning,我创建了一个按数字ID分区的表: CREATE TABLE mytable ( ... `id` int(11) DEFAULT NULL ... ) ENGINE=InnoDB DEFAULT CHARSET=latin1 PARTITION BY HASH (`id`) PARTITIONS 100 我没有主键,但有很多索引。目前,我的表中没有id小于0或大于30的数据,我希望这会增加。我的大多数查询首先包含id以减少搜索空间 我认为一个选择Differentied from mytabl

我创建了一个按数字ID分区的表:

CREATE TABLE mytable (
...
`id` int(11) DEFAULT NULL
...
) ENGINE=InnoDB DEFAULT CHARSET=latin1 PARTITION BY HASH (`id`) PARTITIONS 100
我没有主键,但有很多索引。目前,我的表中没有id小于0或大于30的数据,我希望这会增加。我的大多数查询首先包含id以减少搜索空间

我认为一个选择Differentied from mytable的查询只会返回包含数据的分区数。我感到惊讶的是,关于这一点的解释反而对数据进行了全面扫描:

explain partitions select distinct(id) from mytable;

|  1 | SIMPLE      | mytable | p0,p1,p2,p3,p4,p5,p6,p7,p8,p9,p10,p11,p12,p13,p14,p15,p16,p17,p18,p19,p20,p21,p22,p23,p24,p25,p26,p27,p28,p29,p30,p31,p32,p33,p34,p35,p36,p37,p38,p39,p40,p41,p42,p43,p44,p45,p46,p47,p48,p49,p50,p51,p52,p53,p54,p55,p56,p57,p58,p59,p60,p61,p62,p63,p64,p65,p66,p67,p68,p69,p70,p71,p72,p73,p74,p75,p76,p77,p78,p79,p80,p81,p82,p83,p84,p85,p86,p87,p88,p89,p90,p91,p92,p93,p94,p95,p96,p97,p98,p99 | ALL  | NULL          | NULL | NULL    | NULL | 24667132 | Using temporary |

explain select distinct(id) from mytable;
+----+-------------+----------------------+------+---------------+------+---------+------+----------+-----------------+
| id | select_type | table                | type | possible_keys | key  | key_len | ref  | rows     | Extra           |
+----+-------------+----------------------+------+---------------+------+---------+------+----------+-----------------+
|  1 | SIMPLE      | mytable              | ALL  | NULL          | NULL | NULL    | NULL | 24667132 | Using temporary |
+----+-------------+----------------------+------+---------------+------+---------+------+----------+-----------------+
然后我阅读了答案,它启发了MySQL分区散列函数的工作原理

我的问题是,我如何让MySQL将表中的每个id映射到它自己的分区中,以便使用id进行选择将搜索范围缩小到单个表,而select distinct只需计算分区的数量,而不必扫描它们


我使用的是服务器版本:5.5.35-0ubuntu0.12.04.2ubuntu。

首先,你把两个不同的东西混为一谈。一个是一个SELECT WHERE id=?应该只搜索一个分区。您提到了一些东西,但没有具体说明它当前是否有效,我不明白为什么不应该


第二件事,将SELECT区分为只接触分区信息,与此非常不同。但是,如果我理解正确的话,您假设一个分区只有一种id。不过,哈希分区不是这样工作的。它的工作原理类似于传统的哈希表,它将一个大的键空间映射到一个小的键空间,在您的例子中是100。因此,每个分区将有许多可能的ID。由于mysql不会跟踪哪些可能的ID确实在一个分区中,所以它所能做的就是扫描每个分区,执行DISTINCT并返回结果。也就是说,它可以在单个分区上而不是整个表上执行DISTINCT操作,并且可以并行执行,但是,解释似乎暗示它将创建一个大临时文件来执行DISTINCT操作,可能是因为此优化尚未实现。

确实如此,当我设置select where id=?并解释所考虑的行数只有两行。这正是我所希望的。id不是主键或唯一键,将有许多行具有相同的id。但是,我希望每个分区有一个id。有没有办法指导mysql这样做?给定分区内的所有行都将具有相同的id吗?@Christopher:是的,我认为范围分区应该允许您这样做。只需指定100个分区,每个分区的范围为1。我想您可以指定100个分区,每个分区的范围为1。将有一个可以包含任何ID的溢出分区,因此您的应用程序逻辑必须确保最大ID为100,这将是检查约束,但不幸的是mysql不支持它们。这里不需要使用范围分区。散列分区,正如OP最初创建的那样,将达到预期的效果。@eggyal:是的,我刚刚意识到,把它与键分区混淆了,所以我写的部分内容是错误的。现在已修复。虽然您当前的id值范围整数0到30将分别位于各自的分区中,但在一般情况下,这并不能保证:有2^32个可能的值,被划分为100个分区-因此存在大量冲突的机会。如果不检查实际存储的值,MySQL就无法知道每个分区包含多少。此外,SELECT DISTINCT id FROM mytable返回分区mytable中id的每个不同值,而不是这些值的数量:因此,在任何情况下,仅仅计算分区的数量都是不够的。