MySQL - 使用键分区时数据在分区中的分布不均匀
MySQL - Uneven Distribution of Data into Partitions When Using Key Partitioning
我在 MySQL 5.7.
上使用 InnoDB 引擎
我有一个 table,其中一列是(非唯一的)三字母国家代码(例如 "SGP" 代表新加坡,"JPN"日本等)。
对于我的大部分查询,这个国家代码列是我过滤的第一个 WHERE 子句(例如 WHERE COUNTRY_CODE = 'SGP'
)
因此,我想按此列对 table 进行(子)分区。由于我的大部分查询都针对一个国家代码,因此它们只会以这种方式命中一个分区。
但是,由于有大量不同的国家/地区代码,我不想使用 LIST 分区,因为我必须明确满足每个国家/地区代码的要求。
所以我用的是KEY分区,有8个分区。我认为键分区,即值被散列,会给我一个或多或少的均匀分布在 8 个分区上(不必是完美的)。
但是,我遇到的情况是,在8个分区中,其中4个完全没有动过。
这是我的 CREATE TABLE 语句的摘要:
CREATE TABLE TBL_EATING_PLACES (
ID INT UNSIGNED AUTO_INCREMENT NOT NULL,
TYPE_OF_FOOD SMALLINT UNSIGNED NOT NULL,
SUBTYPE_OF_FOOD SMALLINT UNSIGNED NOT NULL,
COUNTRY_CODE CHAR(3) NOT NULL,
ADDRESS VARCHAR(255),
...
OTHER_NON_RELEVANT_COLUMNS ...,
...,
CONSTRAINT PKEY PRIMARY KEY (ID, TYPE_OF_FOOD, SUBTYPE_OF_FOOD, COUNTRY_CODE)
)
ENGINE = InnoDB
PARTITION BY LIST COLUMNS(TYPE_OF_FOOD, SUBTYPE_OF_FOOD) SUBPARTITION BY KEY(COUNTRY_CODE) SUBPARTITIONS 8 (
PARTITION P_1_1 VALUES IN ((1, 1)),
PARTITION P_1_2 VALUES IN ((1, 2)),
PARTITION P_2_1 VALUES IN ((2, 1)),
PARTITION P_1_2 VALUES IN ((2, 2)),
PARTITION P_1_3 VALUES IN ((2, 2)),
);
我进行 KEY 分区的方式是否有任何问题,以至于它最终只命中了一半的分区?
键分区有什么问题?它提供零收益。不要使用它。相反,提供与您的查询相匹配的合适的复合索引。
(添加以解决评论中的问题...)
通常复合索引可以做与分区相同的事情。 "partition key" 做 "partition pruning" 来选择一个(或几个)分区来查看。通过将 "partition key" 作为索引中的第一列,您可以获得相同的效果。 (是的,也有例外。)
分区有一些开销。每个分区都是一个文件;打开文件是昂贵的。在某些情况下,在进行修剪之前会打开所有分区。以前是INSERT
上没有剪枝。 (讨厌!)(其中一些问题已在较新版本中得到解决,但仍有一些开销。)
我看过很多子分区和非 RANGE 分区的例子。我只看到 4 种情况下索引不会将 "as good" 作为分区。我假设您找到了我的博客,其中列出了 4 个。这是一个副本:Partition Maintenance.
二维搜索需要"reduce the search space"。这是4个案例之一。 RANGE 分区处理一个维度,PRIMARY KEY 处理另一个维度。这对 Find the 10 nearest pizza parlors.
有效(但代码混乱)
BY RANGE 是唯一可以处理 'range' 值(例如日期范围)的分区。 HASH 将简单地搜索 所有 个分区。
BY LIST 可能 与 BY RANGE 一样好,但仅限于精确值。然后我回头说 "why not put the partition key on the front of whatever index you would otherwise use"!
如果有人能找到第 5 个用例,如果没有分区我无法提供同等性能,我会很高兴地扩充我的博客。
我在 MySQL 5.7.
上使用 InnoDB 引擎
我有一个 table,其中一列是(非唯一的)三字母国家代码(例如 "SGP" 代表新加坡,"JPN"日本等)。
对于我的大部分查询,这个国家代码列是我过滤的第一个 WHERE 子句(例如
WHERE COUNTRY_CODE = 'SGP'
)因此,我想按此列对 table 进行(子)分区。由于我的大部分查询都针对一个国家代码,因此它们只会以这种方式命中一个分区。
但是,由于有大量不同的国家/地区代码,我不想使用 LIST 分区,因为我必须明确满足每个国家/地区代码的要求。
所以我用的是KEY分区,有8个分区。我认为键分区,即值被散列,会给我一个或多或少的均匀分布在 8 个分区上(不必是完美的)。
但是,我遇到的情况是,在8个分区中,其中4个完全没有动过。
这是我的 CREATE TABLE 语句的摘要:
CREATE TABLE TBL_EATING_PLACES (
ID INT UNSIGNED AUTO_INCREMENT NOT NULL,
TYPE_OF_FOOD SMALLINT UNSIGNED NOT NULL,
SUBTYPE_OF_FOOD SMALLINT UNSIGNED NOT NULL,
COUNTRY_CODE CHAR(3) NOT NULL,
ADDRESS VARCHAR(255),
...
OTHER_NON_RELEVANT_COLUMNS ...,
...,
CONSTRAINT PKEY PRIMARY KEY (ID, TYPE_OF_FOOD, SUBTYPE_OF_FOOD, COUNTRY_CODE)
)
ENGINE = InnoDB
PARTITION BY LIST COLUMNS(TYPE_OF_FOOD, SUBTYPE_OF_FOOD) SUBPARTITION BY KEY(COUNTRY_CODE) SUBPARTITIONS 8 (
PARTITION P_1_1 VALUES IN ((1, 1)),
PARTITION P_1_2 VALUES IN ((1, 2)),
PARTITION P_2_1 VALUES IN ((2, 1)),
PARTITION P_1_2 VALUES IN ((2, 2)),
PARTITION P_1_3 VALUES IN ((2, 2)),
);
我进行 KEY 分区的方式是否有任何问题,以至于它最终只命中了一半的分区?
键分区有什么问题?它提供零收益。不要使用它。相反,提供与您的查询相匹配的合适的复合索引。
(添加以解决评论中的问题...)
通常复合索引可以做与分区相同的事情。 "partition key" 做 "partition pruning" 来选择一个(或几个)分区来查看。通过将 "partition key" 作为索引中的第一列,您可以获得相同的效果。 (是的,也有例外。)
分区有一些开销。每个分区都是一个文件;打开文件是昂贵的。在某些情况下,在进行修剪之前会打开所有分区。以前是INSERT
上没有剪枝。 (讨厌!)(其中一些问题已在较新版本中得到解决,但仍有一些开销。)
我看过很多子分区和非 RANGE 分区的例子。我只看到 4 种情况下索引不会将 "as good" 作为分区。我假设您找到了我的博客,其中列出了 4 个。这是一个副本:Partition Maintenance.
二维搜索需要"reduce the search space"。这是4个案例之一。 RANGE 分区处理一个维度,PRIMARY KEY 处理另一个维度。这对 Find the 10 nearest pizza parlors.
有效(但代码混乱)BY RANGE 是唯一可以处理 'range' 值(例如日期范围)的分区。 HASH 将简单地搜索 所有 个分区。
BY LIST 可能 与 BY RANGE 一样好,但仅限于精确值。然后我回头说 "why not put the partition key on the front of whatever index you would otherwise use"!
如果有人能找到第 5 个用例,如果没有分区我无法提供同等性能,我会很高兴地扩充我的博客。