使用 MySQL 按空值进行分区

Posted

技术标签:

【中文标题】使用 MySQL 按空值进行分区【英文标题】:Partitions by null values with MySQL 【发布时间】:2015-04-01 12:55:11 【问题描述】:

我有一张桌子:

CREATE TABLE `NewTable` (
    `IBLOCK_ELEMENT_ID`  int(11) NOT NULL ,
    `PROPERTY_1836`  int(11) NULL DEFAULT NULL ,
    `DESCRIPTION_1836`  varchar(255) CHARACTER SET cp1251 COLLATE cp1251_general_ci NULL DEFAULT NULL ,
    `PROPERTY_1837`  int(11) NULL DEFAULT 0 ,
    `DESCRIPTION_1837`  varchar(255) CHARACTER SET cp1251 COLLATE cp1251_general_ci NULL DEFAULT NULL ,
    `PROPERTY_1838`  decimal(18,4) NULL DEFAULT NULL ,
    `DESCRIPTION_1838`  varchar(255) CHARACTER SET cp1251 COLLATE cp1251_general_ci NULL DEFAULT NULL ,
    `PROPERTY_3139`  int(11) NULL DEFAULT 0 ,
    `DESCRIPTION_3139`  varchar(255) CHARACTER SET cp1251 COLLATE cp1251_general_ci NULL DEFAULT NULL ,
    `PROPERTY_3173`  decimal(18,4) NULL DEFAULT NULL ,
    `DESCRIPTION_3173`  varchar(255) CHARACTER SET cp1251 COLLATE cp1251_general_ci NULL DEFAULT NULL ,
    PRIMARY KEY (`IBLOCK_ELEMENT_ID`),
    INDEX `ix_perf_b_iblock_element_pr_1` (`PROPERTY_1837`) USING BTREE ,
    INDEX `ix_perf_b_iblock_element_pr_2` (`PROPERTY_1836`) USING BTREE ,
    INDEX `ix_perf_b_iblock_element_pr_3` (`PROPERTY_3139`) USING BTREE 
)
ENGINE=InnoDB
DEFAULT CHARACTER SET=cp1251 COLLATE=cp1251_general_ci
ROW_FORMAT=COMPACT;

还有一个带有条件的查询:

WHERE PROPERTY_3139 IS NULL

我无法更改表或查询。但我知道,如果我将一个表拆分为 2 个分区 - 只选择可为空值的查询会运行得更快。

我可以使用什么样的技巧来做到这一点? NULL 和 NOT NULL 不是一个范围,我不能将它用作值列表。

【问题讨论】:

如果不能换表,还指望怎么加分区? 对于不准确之处,我深表歉意。我无法更改表格的结构。但分区不会影响查询的任何更改。 为什么这个问题是减号? 我没有否决这个问题。但是“我无法更改表或查询”的问题并没有留下很多改进的选择。 【参考方案1】:

PARTITION 可能没用。

NULL 是 INDEX 中的一个单独值。将 NULL 视为在所有其他值之前存储在 INDEX 中。因此,出于优化目的,IS NULLIS NOT NULL 可以被视为一个“范围”。

但是...如果超过 20%(10%-30%,取决于月相)的表在所需范围内,优化器将决定执行全表扫描更快而不是在 INDEX 和 Data 之间来回弹跳。

回到我的可能...

如果少数行有NULL,索引就可以了;分区不会有太大帮助。 如果中等数量的行具有 NULL,则 PARTITIONing 可以显着提供帮助。 如果大多数行都有 NULL,则全表扫描几乎与扫描一个 PARTITION 的所有内容一样好。

注意:您不能对多个列进行 PARTITION。因此,如果您在PROPERTY_3139 上进行分区,则其余属性将不走运。

【讨论】:

非常感谢您的回答。您的“可能”让我认为重写生成该查询的代码更合理。因为此属性的 Null 值的行更多。 您的 WHERE 子句是否测试一列是否为 NULL?现在是性能问题吗?还是桌子会增长很多?有多少百分比的表有 NULL?如果值得进一步研究,请开始一个新问题,重点关注这些问题的答案。 96% 的行具有 NULL 值(总共 393940 行)。 CMS 生成的查询,将这个表与另一个表连接起来。所以,我认为重写php代码会非常有效。将其分成两个查询 - 第一个将选择所需表的 ID,第二个将获取详细信息。

以上是关于使用 MySQL 按空值进行分区的主要内容,如果未能解决你的问题,请参考以下文章

MYSQL 按空值排序和分组

hive使用动态分区时如果动态分区的字段存在空值的问题

mysql表分区使用及详细介绍

mysql水平分表和分区有啥区别

如何在 PySpark 中的每个分区中回填空值

Mysql按时间进行表分区